/***************************************************************************

NeoGeo 'C' ROM encryption

Starting with KOF99, all NeoGeo games have encrypted graphics. Additionally
to that, the data for the front text layer, which was previously stored in
a separate ROM, is stored at the end of the tile data.

The encryption is one of the nastiest implementation of a XOR scheme ever
seen, involving 9 seemingly uncorrelated 256-byte tables. All known games use
the same tables except KOF2000 and MS4 which use a different set.

The 32 data bits of every longword are decrypted in a single step (one byte at
a time), but the values to use for the xor are determined in a convoluted way.
It's actually so convoluted that it's too difficult to describe - please refer
to the source below.
Suffice to say that bytes are handled in couples (0&3 and 1&2), and the two xor
values are taken from three tables, the indexes inside the tables depending on
bits 0-7 and 8-15 of the address, in one case further xored through the table
used in step 5) below. Additionally, the bytes in a couple can be swapped,
depending either on bit 8 of the address, or on bit 16 xored with the table
used in step 4) below.

The 24 address bits are encrypted in five steps. Each step xors 8 bits with a
value taken from a different table; the index inside the table depends on 8
other bits.
0) xor bits  0-7  with a fixed value that changes from game to game
1) xor bits  8-15 depending on bits 16-23
2) xor bits  8-15 depending on bits  0-7
3) xor bits 16-23 depending on bits  0-7
4) xor bits 16-23 depending on bits  8-15
5) xor bits  0-7  depending on bits  8-15

Each step acts on the current value, so e.g. step 4) uses bits 8-15 as modified
by step 2).

[Note: the table used in step 1) is currently incomplete due to lack of data to
analyze]


There are two major weaknesses in this encryption algorithm, that exposed it to
a known plaintext attack.

The first weakness is that the data xor depends on the address inside the
encrypted ROM instead that on the decrypted address; together with the high
concentration of 0x00 and 0xFF in the decrypted data (more than 60% of the
total), this exposed easily recognizable patterns in the encrypted data, which
could be exploited with some simple statistical checks. The deviousness of the
xor scheme was the major difficulty.

The second weakness is that the address scrambling works on 32-bit words. Since
there are a large number of 32-bit values that appear only once in the whole
encrypted ROM space, this means that once the xor layer was broken, a large
table of encrypted-decrypted address correspondencies could be built and
analyzed, quickly leading to the algorithm.

***************************************************************************/

#include "driver.h"
#include "neogeo.h"


const unsigned char *type0_t03;
const unsigned char *type0_t12;
const unsigned char *type1_t03;
const unsigned char *type1_t12;
const unsigned char *address_8_15_xor1;
const unsigned char *address_8_15_xor2;
const unsigned char *address_16_23_xor1;
const unsigned char *address_16_23_xor2;
const unsigned char *address_0_7_xor;


const unsigned char kof99_type0_t03[256] =
{
	0xfb, 0x86, 0x9d, 0xf1, 0xbf, 0x80, 0xd5, 0x43, 0xab, 0xb3, 0x9f, 0x6a, 0x33, 0xd9, 0xdb, 0xb6,
	0x66, 0x08, 0x69, 0x88, 0xcc, 0xb7, 0xde, 0x49, 0x97, 0x64, 0x1f, 0xa6, 0xc0, 0x2f, 0x52, 0x42,
	0x44, 0x5a, 0xf2, 0x28, 0x98, 0x87, 0x96, 0x8a, 0x83, 0x0b, 0x03, 0x61, 0x71, 0x99, 0x6b, 0xb5,
	0x1a, 0x8e, 0xfe, 0x04, 0xe1, 0xf7, 0x7d, 0xdd, 0xed, 0xca, 0x37, 0xfc, 0xef, 0x39, 0x72, 0xda,
	0xb8, 0xbe, 0xee, 0x7f, 0xe5, 0x31, 0x78, 0xf3, 0x91, 0x9a, 0xd2, 0x11, 0x19, 0xb9, 0x09, 0x4c,
	0xfd, 0x6d, 0x2a, 0x4d, 0x65, 0xa1, 0x89, 0xc7, 0x75, 0x50, 0x21, 0xfa, 0x16, 0x00, 0xe9, 0x12,
	0x74, 0x2b, 0x1e, 0x4f, 0x14, 0x01, 0x70, 0x3a, 0x4e, 0x3f, 0xf5, 0xf4, 0x1d, 0x3d, 0x15, 0x27,
	0xa7, 0xff, 0x45, 0xe0, 0x6e, 0xf9, 0x54, 0xc8, 0x48, 0xad, 0xa5, 0x0a, 0xf6, 0x2d, 0x2c, 0xe2,
	0x68, 0x67, 0xd6, 0x85, 0xb4, 0xc3, 0x34, 0xbc, 0x62, 0xd3, 0x5f, 0x84, 0x06, 0x5b, 0x0d, 0x95,
	0xea, 0x5e, 0x9e, 0xd4, 0xeb, 0x90, 0x7a, 0x05, 0x81, 0x57, 0xe8, 0x60, 0x2e, 0x20, 0x25, 0x7c,
	0x46, 0x0c, 0x93, 0xcb, 0xbd, 0x17, 0x7e, 0xec, 0x79, 0xb2, 0xc2, 0x22, 0x41, 0xb1, 0x10, 0xac,
	0xa8, 0xbb, 0x9b, 0x82, 0x4b, 0x9c, 0x8b, 0x07, 0x47, 0x35, 0x24, 0x56, 0x8d, 0xaf, 0xe6, 0x26,
	0x40, 0x38, 0xc4, 0x5d, 0x1b, 0xc5, 0xd1, 0x0f, 0x6c, 0x7b, 0xb0, 0xe3, 0xa3, 0x23, 0x6f, 0x58,
	0xc1, 0xba, 0xcf, 0xd7, 0xa2, 0xe7, 0xd0, 0x63, 0x5c, 0xf8, 0x73, 0xa0, 0x13, 0xdc, 0x29, 0xcd,
	0xc9, 0x76, 0xae, 0x8f, 0xe4, 0x59, 0x30, 0xaa, 0x94, 0x1c, 0x3c, 0x0e, 0x55, 0x92, 0x77, 0x32,
	0xc6, 0xce, 0x18, 0x36, 0xdf, 0xa9, 0x8c, 0xd8, 0xa4, 0xf0, 0x3b, 0x51, 0x4a, 0x02, 0x3e, 0x53,
};

const unsigned char kof99_type0_t12[256] =
{
	0x1f, 0xac, 0x4d, 0xcd, 0xca, 0x70, 0x02, 0x6b, 0x18, 0x40, 0x62, 0xb2, 0x3f, 0x9b, 0x5b, 0xef,
	0x69, 0x68, 0x71, 0x3b, 0xcb, 0xd4, 0x30, 0xbc, 0x47, 0x72, 0x74, 0x5e, 0x84, 0x4c, 0x1b, 0xdb,
	0x6a, 0x35, 0x1d, 0xf5, 0xa1, 0xb3, 0x87, 0x5d, 0x57, 0x28, 0x2f, 0xc4, 0xfd, 0x24, 0x26, 0x36,
	0xad, 0xbe, 0x61, 0x63, 0x73, 0xaa, 0x82, 0xee, 0x29, 0xd0, 0xdf, 0x8c, 0x15, 0xb5, 0x96, 0xf3,
	0xdd, 0x7e, 0x3a, 0x37, 0x58, 0x7f, 0x0c, 0xfc, 0x0b, 0x07, 0xe8, 0xf7, 0xf4, 0x14, 0xb8, 0x81,
	0xb6, 0xd7, 0x1e, 0xc8, 0x85, 0xe6, 0x9d, 0x33, 0x60, 0xc5, 0x95, 0xd5, 0x55, 0x00, 0xa3, 0xb7,
	0x7d, 0x50, 0x0d, 0xd2, 0xc1, 0x12, 0xe5, 0xed, 0xd8, 0xa4, 0x9c, 0x8f, 0x2a, 0x4f, 0xa8, 0x01,
	0x52, 0x83, 0x65, 0xea, 0x9a, 0x6c, 0x44, 0x4a, 0xe2, 0xa5, 0x2b, 0x46, 0xe1, 0x34, 0x25, 0xf8,
	0xc3, 0xda, 0xc7, 0x6e, 0x48, 0x38, 0x7c, 0x78, 0x06, 0x53, 0x64, 0x16, 0x98, 0x3c, 0x91, 0x42,
	0x39, 0xcc, 0xb0, 0xf1, 0xeb, 0x13, 0xbb, 0x05, 0x32, 0x86, 0x0e, 0xa2, 0x0a, 0x9e, 0xfa, 0x66,
	0x54, 0x8e, 0xd3, 0xe7, 0x19, 0x20, 0x77, 0xec, 0xff, 0xbd, 0x6d, 0x43, 0x23, 0x03, 0xab, 0x75,
	0x3d, 0xcf, 0xd1, 0xde, 0x92, 0x31, 0xa7, 0x45, 0x4b, 0xc2, 0x97, 0xf9, 0x7a, 0x88, 0xd9, 0x1c,
	0xe9, 0xe4, 0x10, 0xc9, 0x22, 0x2d, 0x90, 0x76, 0x17, 0x79, 0x04, 0x51, 0x1a, 0x5a, 0x5f, 0x2c,
	0x21, 0x6f, 0x3e, 0xe0, 0xf0, 0xbf, 0xd6, 0x94, 0x0f, 0x80, 0x11, 0xa0, 0x5c, 0xa9, 0x49, 0x2e,
	0xce, 0xaf, 0xa6, 0x9f, 0x7b, 0x99, 0xb9, 0xb4, 0xe3, 0xfb, 0xf6, 0x27, 0xf2, 0x93, 0xfe, 0x08,
	0x67, 0xae, 0x09, 0x89, 0xdc, 0x4e, 0xc6, 0xc0, 0x8a, 0xb1, 0x59, 0x8b, 0x41, 0x56, 0x8d, 0xba,
};

const unsigned char kof99_type1_t03[256] =
{
	0xa9, 0x17, 0xaf, 0x0d, 0x34, 0x6e, 0x53, 0xb6, 0x7f, 0x58, 0xe9, 0x14, 0x5f, 0x55, 0xdb, 0xd4,
	0x42, 0x80, 0x99, 0x59, 0xa8, 0x3a, 0x57, 0x5d, 0xd5, 0x6f, 0x4c, 0x68, 0x35, 0x46, 0xa6, 0xe7,
	0x7b, 0x71, 0xe0, 0x93, 0xa2, 0x1f, 0x64, 0x21, 0xe3, 0xb1, 0x98, 0x26, 0xab, 0xad, 0xee, 0xe5,
	0xbb, 0xd9, 0x1e, 0x2e, 0x95, 0x36, 0xef, 0x23, 0x79, 0x45, 0x04, 0xed, 0x13, 0x1d, 0xf4, 0x85,
	0x96, 0xec, 0xc2, 0x32, 0xaa, 0x7c, 0x15, 0xd8, 0xda, 0x92, 0x90, 0x9d, 0xb7, 0x56, 0x6a, 0x66,
	0x41, 0xfc, 0x00, 0xf6, 0x50, 0x24, 0xcf, 0xfb, 0x11, 0xfe, 0x82, 0x48, 0x9b, 0x27, 0x1b, 0x67,
	0x4e, 0x84, 0x69, 0x97, 0x6d, 0x8c, 0xd2, 0xba, 0x74, 0xf9, 0x8f, 0xa5, 0x54, 0x5c, 0xcd, 0x73,
	0x07, 0xd1, 0x01, 0x09, 0xf1, 0x19, 0x3b, 0x5e, 0x87, 0x30, 0x76, 0xcc, 0xc0, 0x5a, 0xa7, 0x49,
	0x22, 0xfa, 0x16, 0x02, 0xdf, 0xa4, 0xff, 0xb3, 0x75, 0x33, 0xbd, 0x88, 0x2f, 0xcb, 0x2a, 0x44,
	0xb8, 0xbf, 0x1c, 0x0f, 0x81, 0x10, 0x43, 0xb4, 0xc8, 0x7e, 0x9a, 0x25, 0xea, 0x83, 0x4b, 0x38,
	0x7a, 0xd7, 0x3d, 0x1a, 0x4f, 0x62, 0x51, 0xc9, 0x47, 0x0e, 0xce, 0x3f, 0xc7, 0x4d, 0x2c, 0xa1,
	0x86, 0xb9, 0xc5, 0xca, 0xdd, 0x6b, 0x70, 0x6c, 0x91, 0x9c, 0xbe, 0x0a, 0x9f, 0xf5, 0x94, 0xbc,
	0x18, 0x2b, 0x60, 0x20, 0x29, 0xf7, 0xf2, 0x28, 0xc4, 0xa0, 0x0b, 0x65, 0xde, 0x8d, 0x78, 0x12,
	0x3e, 0xd0, 0x77, 0x08, 0x8b, 0xae, 0x05, 0x31, 0x3c, 0xd6, 0xa3, 0x89, 0x06, 0xdc, 0x52, 0x72,
	0xb0, 0xb5, 0x37, 0xd3, 0xc3, 0x8a, 0xc6, 0xf0, 0xc1, 0x61, 0xfd, 0x4a, 0x5b, 0x7d, 0x9e, 0xf3,
	0x63, 0x40, 0x2d, 0xe8, 0xb2, 0xe6, 0x39, 0x03, 0xeb, 0x8e, 0xe1, 0x0c, 0xe4, 0xe2, 0xf8, 0xac,
};

const unsigned char kof99_type1_t12[256] =
{
	0xea, 0xe6, 0x5e, 0xa7, 0x8e, 0xac, 0x34, 0x03, 0x30, 0x97, 0x52, 0x53, 0x76, 0xf2, 0x62, 0x0b,
	0x0a, 0xfc, 0x94, 0xb8, 0x67, 0x36, 0x11, 0xbc, 0xae, 0xca, 0xfa, 0x15, 0x04, 0x2b, 0x17, 0xc4,
	0x3e, 0x5b, 0x59, 0x01, 0x57, 0xe2, 0xba, 0xb7, 0xd1, 0x3f, 0xf0, 0x6a, 0x9c, 0x2a, 0xcb, 0xa9,
	0xe3, 0x2c, 0xc0, 0x0f, 0x46, 0x91, 0x8a, 0xd0, 0x98, 0xc5, 0xa6, 0x1b, 0x96, 0x29, 0x12, 0x09,
	0x63, 0xed, 0xe0, 0xa2, 0x86, 0x77, 0xbe, 0xe5, 0x65, 0xdb, 0xbd, 0x50, 0xb3, 0x9d, 0x1a, 0x4e,
	0x79, 0x0c, 0x00, 0x43, 0xdf, 0x3d, 0x54, 0x33, 0x8f, 0x89, 0xa8, 0x7b, 0xf9, 0xd5, 0x27, 0x82,
	0xbb, 0xc2, 0x8c, 0x47, 0x88, 0x6b, 0xb4, 0xc3, 0xf8, 0xaa, 0x06, 0x1e, 0x83, 0x7d, 0x05, 0x78,
	0x85, 0xf6, 0x6e, 0x2e, 0xec, 0x5a, 0x31, 0x45, 0x38, 0x14, 0x16, 0x8b, 0x02, 0xe4, 0x4f, 0xb0,
	0xbf, 0xab, 0xa4, 0x9e, 0x48, 0x60, 0x19, 0x35, 0x08, 0xde, 0xdd, 0x66, 0x90, 0x51, 0xcc, 0xa3,
	0xaf, 0x70, 0x9b, 0x75, 0x95, 0x49, 0x6c, 0x64, 0x72, 0x7e, 0x44, 0xa0, 0x73, 0x25, 0x68, 0x55,
	0x1f, 0x40, 0x7a, 0x74, 0x0e, 0x8d, 0xdc, 0x1c, 0x71, 0xc8, 0xcf, 0xd7, 0xe8, 0xce, 0xeb, 0x32,
	0x3a, 0xee, 0x07, 0x61, 0x4d, 0xfe, 0x5c, 0x7c, 0x56, 0x2f, 0x2d, 0x5f, 0x6f, 0x9f, 0x81, 0x22,
	0x58, 0x4b, 0xad, 0xda, 0xb9, 0x10, 0x18, 0x23, 0xe1, 0xf3, 0x6d, 0xe7, 0xe9, 0x28, 0xd6, 0xd8,
	0xf4, 0x4c, 0x39, 0x21, 0xb2, 0x84, 0xc1, 0x24, 0x26, 0xf1, 0x93, 0x37, 0xc6, 0x4a, 0xcd, 0x20,
	0xc9, 0xd9, 0xc7, 0xb1, 0xff, 0x99, 0xd4, 0x5d, 0xb5, 0xa1, 0x87, 0x0d, 0x69, 0x92, 0x13, 0x80,
	0xd2, 0xd3, 0xfd, 0x1d, 0xf5, 0x3b, 0xa5, 0x7f, 0xef, 0x9a, 0xb6, 0x42, 0xfb, 0x3c, 0xf7, 0x41,
};



/* underlined values are wrong (not enough evidence, FF fill in kof99 and garou) */
/* they correspond to tiles 7d000-7efff */
const unsigned char kof99_address_8_15_xor1[256] =
{
	0x00, 0xb1, 0x1e, 0xc5, 0x3d, 0x40, 0x45, 0x5e, 0xf2, 0xf8, 0x04, 0x63, 0x36, 0x87, 0x88, 0xbf,
	0xab, 0xcc, 0x78, 0x08, 0xdd, 0x20, 0xd4, 0x35, 0x09, 0x8e, 0x44, 0xae, 0x33, 0xa9, 0x9e, 0xcd,
	0xb3, 0xe5, 0xad, 0x41, 0xda, 0xbe, 0xf4, 0x16, 0x57, 0x2e, 0x53, 0x67, 0xaf, 0xdb, 0x8a, 0xd8,
	0x34, 0x17, 0x3c, 0x01, 0x55, 0x73, 0xcf, 0xe3, 0xe8, 0xc7, 0x0d, 0xe9, 0xa3, 0x13, 0x0c, 0xf6,
	0x90, 0x4e, 0xfb, 0x97, 0x6d, 0x5f, 0xa8, 0x71, 0x11, 0xfc, 0xd1, 0x95, 0x81, 0xba, 0x8c, 0x1b,
	0x39, 0xfe, 0xa2, 0x15, 0xa6, 0x52, 0x4d, 0x5b, 0x59, 0xa5, 0xe0, 0x96, 0xd9, 0x8f, 0x7b, 0xed,
	0x29, 0xd3, 0x1f, 0x0e, 0xec, 0x23, 0x0f, 0xb8, 0x6c, 0x6f, 0x7d, 0x18, 0x46, 0xd6, 0xe4, 0xb5,
	0x9a, 0x79, 0x02, 0xf5, 0x03, 0xc0, 0x60, 0x66, 0x5c, 0x2f, 0x76, 0x85, 0x9d, 0x54, 0x1a, 0x6a,
	0x28, 0xce, 0x7f, 0x7c, 0x91, 0x99, 0x4c, 0x83, 0x3e, 0xb4, 0x1d, 0x05, 0xc1, 0xc3, 0xd7, 0x47,
	0xde, 0xbc, 0x62, 0x6e, 0x86, 0x14, 0x80, 0x77, 0xeb, 0xf3, 0x07, 0x31, 0x56, 0xd2, 0xc2, 0xc6,
	0x6b, 0xdc, 0xfd, 0x22, 0x92, 0xf0, 0x06, 0x51, 0x2d, 0x38, 0xe6, 0xa0, 0x25, 0xdf, 0xd5, 0x2c,
	0x1c, 0x94, 0x12, 0x9c, 0xb0, 0x9b, 0xc4, 0x0b, 0xc8, 0xd0, 0xf7, 0x30, 0xcb, 0x27, 0xfa, 0x7a,
	0x10, 0x61, 0xaa, 0xa4, 0x70, 0xb7, 0x2a, 0x5a, 0xc9, 0xf1, 0x0a, 0x49, 0x65, 0xee, 0x69, 0x4b,
	0x3a, 0x8d, 0x32, 0x5d, 0x68, 0xb9, 0x9f, 0x75, 0x19, 0x3f, 0xac, 0x37, 0x4f, 0xe7, 0x93, 0x89,
	0x7e, 0x4a, 0x3b, 0xea, 0x74, 0x72, 0x43, 0xbd, 0x24, 0xef, 0xb6, 0xff, 0x64, 0x58, 0x84, 0x8b,
	0xa7, 0xbb, 0xb2, 0xe1, 0x26, 0x2b, 0x50, 0xca, 0x21, 0xf9, 0x98, 0xa1, 0xe2, 0x42, 0x82, 0x48,
/*	                                                            ^^^^  ^^^^  ^^^^  ^^^^*/
};

const unsigned char kof99_address_8_15_xor2[256] =
{
	0x9b, 0x9d, 0xc1, 0x3d, 0xa9, 0xb8, 0xf4, 0x6f, 0xf6, 0x25, 0xc7, 0x47, 0xd5, 0x97, 0xdf, 0x6b,
	0xeb, 0x90, 0xa4, 0xb2, 0x5d, 0xf5, 0x66, 0xb0, 0xb9, 0x8b, 0x93, 0x64, 0xec, 0x7b, 0x65, 0x8c,
	0xf1, 0x43, 0x42, 0x6e, 0x45, 0x9f, 0xb3, 0x35, 0x06, 0x71, 0x96, 0xdb, 0xa0, 0xfb, 0x0b, 0x3a,
	0x1f, 0xf8, 0x8e, 0x69, 0xcd, 0x26, 0xab, 0x86, 0xa2, 0x0c, 0xbd, 0x63, 0xa5, 0x7a, 0xe7, 0x6a,
	0x5f, 0x18, 0x9e, 0xbf, 0xad, 0x55, 0xb1, 0x1c, 0x5c, 0x03, 0x30, 0xc6, 0x37, 0x20, 0xe3, 0xc9,
	0x52, 0xe8, 0xee, 0x4f, 0x01, 0x70, 0xc4, 0x77, 0x29, 0x2a, 0xba, 0x53, 0x12, 0x04, 0x7d, 0xaf,
	0x33, 0x8f, 0xa8, 0x4d, 0xaa, 0x5b, 0xb4, 0x0f, 0x92, 0xbb, 0xed, 0xe1, 0x2f, 0x50, 0x6c, 0xd2,
	0x2c, 0x95, 0xd9, 0xf9, 0x98, 0xc3, 0x76, 0x4c, 0xf2, 0xe4, 0xe5, 0x2b, 0xef, 0x9c, 0x49, 0xb6,
	0x31, 0x3b, 0xbc, 0xa1, 0xca, 0xde, 0x62, 0x74, 0xea, 0x81, 0x00, 0xdd, 0xa6, 0x46, 0x88, 0x3f,
	0x39, 0xd6, 0x23, 0x54, 0x24, 0x4a, 0xd8, 0xdc, 0xd7, 0xd1, 0xcc, 0xbe, 0x57, 0x7c, 0xda, 0x44,
	0x61, 0xce, 0xd3, 0xd4, 0xe9, 0x28, 0x80, 0xe0, 0x56, 0x8a, 0x09, 0x05, 0x9a, 0x89, 0x1b, 0xf7,
	0xf3, 0x99, 0x6d, 0x5e, 0x48, 0x91, 0xc0, 0xd0, 0xc5, 0x79, 0x78, 0x41, 0x59, 0x21, 0x2e, 0xff,
	0xc2, 0x4b, 0x38, 0x83, 0x32, 0xe6, 0xe2, 0x7f, 0x1e, 0x17, 0x58, 0x1d, 0x1a, 0xfa, 0x85, 0x82,
	0x94, 0xc8, 0x72, 0x7e, 0xb7, 0xac, 0x0e, 0xfc, 0xfd, 0x16, 0x27, 0x75, 0x8d, 0xcb, 0x08, 0xfe,
	0x0a, 0x02, 0x0d, 0x36, 0x11, 0x22, 0x84, 0x40, 0x34, 0x3e, 0x2d, 0x68, 0x5a, 0xa7, 0x67, 0xae,
	0x87, 0x07, 0x10, 0x60, 0x14, 0x73, 0x3c, 0x51, 0x19, 0xa3, 0xb5, 0xcf, 0x13, 0xf0, 0x15, 0x4e,
};

const unsigned char kof99_address_16_23_xor1[256] =
{
	0x00, 0x5f, 0x03, 0x52, 0xce, 0xe3, 0x7d, 0x8f, 0x6b, 0xf8, 0x20, 0xde, 0x7b, 0x7e, 0x39, 0xbe,
	0xf5, 0x94, 0x18, 0x78, 0x80, 0xc9, 0x7f, 0x7a, 0x3e, 0x63, 0xf2, 0xe0, 0x4e, 0xf7, 0x87, 0x27,
	0x69, 0x6c, 0xa4, 0x1d, 0x85, 0x5b, 0xe6, 0x44, 0x25, 0x0c, 0x98, 0xc7, 0x01, 0x02, 0xa3, 0x26,
	0x09, 0x38, 0xdb, 0xc3, 0x1e, 0xcf, 0x23, 0x45, 0x68, 0x76, 0xd6, 0x22, 0x5d, 0x5a, 0xae, 0x16,
	0x9f, 0xa2, 0xb5, 0xcd, 0x81, 0xea, 0x5e, 0xb8, 0xb9, 0x9d, 0x9c, 0x1a, 0x0f, 0xff, 0xe1, 0xe7,
	0x74, 0xaa, 0xd4, 0xaf, 0xfc, 0xc6, 0x33, 0x29, 0x5c, 0xab, 0x95, 0xf0, 0x19, 0x47, 0x59, 0x67,
	0xf3, 0x96, 0x60, 0x1f, 0x62, 0x92, 0xbd, 0x89, 0xee, 0x28, 0x13, 0x06, 0xfe, 0xfa, 0x32, 0x6d,
	0x57, 0x3c, 0x54, 0x50, 0x2c, 0x58, 0x49, 0xfb, 0x17, 0xcc, 0xef, 0xb2, 0xb4, 0xf9, 0x07, 0x70,
	0xc5, 0xa9, 0xdf, 0xd5, 0x3b, 0x86, 0x2b, 0x0d, 0x6e, 0x4d, 0x0a, 0x90, 0x43, 0x31, 0xc1, 0xf6,
	0x88, 0x0b, 0xda, 0x53, 0x14, 0xdc, 0x75, 0x8e, 0xb0, 0xeb, 0x99, 0x46, 0xa1, 0x15, 0x71, 0xc8,
	0xe9, 0x3f, 0x4a, 0xd9, 0x73, 0xe5, 0x7c, 0x30, 0x77, 0xd3, 0xb3, 0x4b, 0x37, 0x72, 0xc2, 0x04,
	0x97, 0x08, 0x36, 0xb1, 0x3a, 0x61, 0xec, 0xe2, 0x1c, 0x9a, 0x8b, 0xd1, 0x1b, 0x2e, 0x9e, 0x8a,
	0xd8, 0x41, 0xe4, 0xc4, 0x40, 0x2f, 0xad, 0xc0, 0xb6, 0x84, 0x51, 0x66, 0xbb, 0x12, 0xe8, 0xdd,
	0xcb, 0xbc, 0x6f, 0xd0, 0x11, 0x83, 0x56, 0x4c, 0xca, 0xbf, 0x05, 0x10, 0xd7, 0xba, 0xfd, 0xed,
	0x8c, 0x0e, 0x4f, 0x3d, 0x35, 0x91, 0xb7, 0xac, 0x34, 0x64, 0x2a, 0xf1, 0x79, 0x6a, 0x9b, 0x2d,
	0x65, 0xf4, 0x42, 0xa0, 0x8d, 0xa7, 0x48, 0x55, 0x21, 0x93, 0x24, 0xd2, 0xa6, 0xa5, 0xa8, 0x82,
};

const unsigned char kof99_address_16_23_xor2[256] =
{
	0x29, 0x97, 0x1a, 0x2c, 0x0b, 0x94, 0x3e, 0x75, 0x01, 0x0d, 0x1b, 0xe1, 0x4d, 0x38, 0x39, 0x8f,
	0xe7, 0xd0, 0x60, 0x90, 0xb2, 0x0f, 0xbb, 0x70, 0x1f, 0xe6, 0x5b, 0x87, 0xb4, 0x43, 0xfd, 0xf5,
	0xf6, 0xf9, 0xad, 0xc0, 0x98, 0x17, 0x9f, 0x91, 0x15, 0x51, 0x55, 0x64, 0x6c, 0x18, 0x61, 0x0e,
	0xd9, 0x93, 0xab, 0xd6, 0x24, 0x2f, 0x6a, 0x3a, 0x22, 0xb1, 0x4f, 0xaa, 0x23, 0x48, 0xed, 0xb9,
	0x88, 0x8b, 0xa3, 0x6b, 0x26, 0x4c, 0xe8, 0x2d, 0x1c, 0x99, 0xbd, 0x5c, 0x58, 0x08, 0x50, 0xf2,
	0x2a, 0x62, 0xc1, 0x72, 0x66, 0x04, 0x10, 0x37, 0x6e, 0xfc, 0x44, 0xa9, 0xdf, 0xd4, 0x20, 0xdd,
	0xee, 0x41, 0xdb, 0x73, 0xde, 0x54, 0xec, 0xc9, 0xf3, 0x4b, 0x2e, 0xae, 0x5a, 0x4a, 0x5e, 0x47,
	0x07, 0x2b, 0x76, 0xa4, 0xe3, 0x28, 0xfe, 0xb0, 0xf0, 0x02, 0x06, 0xd1, 0xaf, 0x42, 0xc2, 0xa5,
	0xe0, 0x67, 0xbf, 0x16, 0x8e, 0x35, 0xce, 0x8a, 0xe5, 0x3d, 0x7b, 0x96, 0xd7, 0x79, 0x52, 0x1e,
	0xa1, 0xfb, 0x9b, 0xbe, 0x21, 0x9c, 0xe9, 0x56, 0x14, 0x7f, 0xa0, 0xe4, 0xc3, 0xc4, 0x46, 0xea,
	0xf7, 0xd2, 0x1d, 0x31, 0x0a, 0x5f, 0xeb, 0xa2, 0x68, 0x8d, 0xb5, 0xc5, 0x74, 0x0c, 0xdc, 0x82,
	0x80, 0x09, 0x19, 0x95, 0x71, 0x9a, 0x11, 0x57, 0x77, 0x4e, 0xc6, 0xff, 0x12, 0x03, 0xa7, 0xc7,
	0xf4, 0xc8, 0xb6, 0x7a, 0x59, 0x36, 0x3c, 0x53, 0xe2, 0x69, 0x8c, 0x25, 0x05, 0x45, 0x63, 0xf8,
	0x34, 0x89, 0x33, 0x3f, 0x85, 0x27, 0xbc, 0x65, 0xfa, 0xa8, 0x6d, 0x84, 0x5d, 0xba, 0x40, 0x32,
	0x30, 0xef, 0x83, 0x13, 0xa6, 0x78, 0xcc, 0x81, 0x9e, 0xda, 0xca, 0xd3, 0x7e, 0x9d, 0x6f, 0xcd,
	0xb7, 0xb3, 0xd8, 0xcf, 0x3b, 0x00, 0x92, 0xb8, 0x86, 0xac, 0x49, 0x7c, 0xf1, 0xd5, 0xcb, 0x7d,
};

const unsigned char kof99_address_0_7_xor[256] =
{
	0x74, 0xad, 0x5d, 0x1d, 0x9e, 0xc3, 0xfa, 0x4e, 0xf7, 0xdb, 0xca, 0xa2, 0x64, 0x36, 0x56, 0x0c,
	0x4f, 0xcf, 0x43, 0x66, 0x1e, 0x91, 0xe3, 0xa5, 0x58, 0xc2, 0xc1, 0xd4, 0xb9, 0xdd, 0x76, 0x16,
	0xce, 0x61, 0x75, 0x01, 0x2b, 0x22, 0x38, 0x55, 0x50, 0xef, 0x6c, 0x99, 0x05, 0xe9, 0xe8, 0xe0,
	0x2d, 0xa4, 0x4b, 0x4a, 0x42, 0xae, 0xba, 0x8c, 0x6f, 0x93, 0x14, 0xbd, 0x71, 0x21, 0xb0, 0x02,
	0x15, 0xc4, 0xe6, 0x60, 0xd7, 0x44, 0xfd, 0x85, 0x7e, 0x78, 0x8f, 0x00, 0x81, 0xf1, 0xa7, 0x3b,
	0xa0, 0x10, 0xf4, 0x9f, 0x39, 0x88, 0x35, 0x62, 0xcb, 0x19, 0x31, 0x11, 0x51, 0xfb, 0x2a, 0x20,
	0x45, 0xd3, 0x7d, 0x92, 0x1b, 0xf2, 0x09, 0x0d, 0x97, 0xa9, 0xb5, 0x3c, 0xee, 0x5c, 0xaf, 0x7b,
	0xd2, 0x3a, 0x49, 0x8e, 0xb6, 0xcd, 0xd9, 0xde, 0x8a, 0x29, 0x6e, 0xd8, 0x0b, 0xe1, 0x69, 0x87,
	0x1a, 0x96, 0x18, 0xcc, 0xdf, 0xe7, 0xc5, 0xc7, 0xf8, 0x52, 0xc9, 0xf0, 0xb7, 0xe5, 0x33, 0xda,
	0x67, 0x9d, 0xa3, 0x03, 0x0e, 0x72, 0x26, 0x79, 0xe2, 0xb8, 0xfc, 0xaa, 0xfe, 0xb4, 0x86, 0xc8,
	0xd1, 0xbc, 0x12, 0x08, 0x77, 0xeb, 0x40, 0x8d, 0x04, 0x25, 0x4d, 0x5a, 0x6a, 0x7a, 0x2e, 0x41,
	0x65, 0x1c, 0x13, 0x94, 0xb2, 0x63, 0x28, 0x59, 0x5e, 0x9a, 0x30, 0x07, 0xc6, 0xbf, 0x17, 0xf5,
	0x0f, 0x89, 0xf3, 0x1f, 0xea, 0x6d, 0xb3, 0xc0, 0x70, 0x47, 0xf9, 0x53, 0xf6, 0xd6, 0x54, 0xed,
	0x6b, 0x4c, 0xe4, 0x8b, 0x83, 0x24, 0x90, 0xb1, 0x7c, 0xbb, 0x73, 0xab, 0xd5, 0x2f, 0x5f, 0xec,
	0x9c, 0x2c, 0xa8, 0x34, 0x46, 0x37, 0x27, 0xa1, 0x0a, 0x06, 0x80, 0x68, 0x82, 0x32, 0x84, 0xff,
	0x48, 0xac, 0x7f, 0x3f, 0x95, 0xdc, 0x98, 0x9b, 0xbe, 0x23, 0x57, 0x3e, 0x5b, 0xd0, 0x3d, 0xa6,
};






const unsigned char kof2000_type0_t03[256] =
{
	0x10, 0x61, 0xf1, 0x78, 0x85, 0x52, 0x68, 0xe3, 0x12, 0x0d, 0xfa, 0xf0, 0xc9, 0x36, 0x5e, 0x3d,
	0xf9, 0xa6, 0x01, 0x2e, 0xc7, 0x84, 0xea, 0x2b, 0x6d, 0x14, 0x38, 0x4f, 0x55, 0x1c, 0x9d, 0xa7,
	0x7a, 0xc6, 0xf8, 0x9a, 0xe6, 0x42, 0xb5, 0xed, 0x7d, 0x3a, 0xb1, 0x05, 0x43, 0x4a, 0x22, 0xfd,
	0xac, 0xa4, 0x31, 0xc3, 0x32, 0x76, 0x95, 0x9e, 0x7e, 0x88, 0x8e, 0xa2, 0x97, 0x18, 0xbe, 0x2a,
	0xf5, 0xd6, 0xca, 0xcc, 0x72, 0x3b, 0x87, 0x6c, 0xde, 0x75, 0xd7, 0x21, 0xcb, 0x0b, 0xdd, 0xe7,
	0xe1, 0x65, 0xaa, 0xb9, 0x44, 0xfb, 0x66, 0x15, 0x1a, 0x3c, 0x98, 0xcf, 0x8a, 0xdf, 0x37, 0xa5,
	0x2f, 0x67, 0xd2, 0x83, 0xb6, 0x6b, 0xfc, 0xe0, 0xb4, 0x7c, 0x08, 0xdc, 0x93, 0x30, 0xab, 0xe4,
	0x19, 0xc2, 0x8b, 0xeb, 0xa0, 0x0a, 0xc8, 0x03, 0xc0, 0x4b, 0x64, 0x71, 0x86, 0x9c, 0x9b, 0x16,
	0x79, 0xff, 0x70, 0x09, 0x8c, 0xd0, 0xf6, 0x53, 0x07, 0x73, 0xd4, 0x89, 0xb3, 0x00, 0xe9, 0xfe,
	0xec, 0x8f, 0xbc, 0xb2, 0x1e, 0x5d, 0x11, 0x35, 0xa9, 0x06, 0x59, 0x9f, 0xc1, 0xd3, 0x7b, 0xf2,
	0xc5, 0x77, 0x4e, 0x39, 0x20, 0xd5, 0x6a, 0x82, 0xda, 0x45, 0xf3, 0x33, 0x81, 0x23, 0xba, 0xe2,
	0x1d, 0x5f, 0x5c, 0x51, 0x49, 0xae, 0x8d, 0xc4, 0xa8, 0xf7, 0x1f, 0x0f, 0x34, 0x28, 0xa1, 0xd9,
	0x27, 0xd8, 0x4c, 0x2c, 0xbf, 0x91, 0x3e, 0x69, 0x57, 0x41, 0x25, 0x0c, 0x5a, 0x90, 0x92, 0xb0,
	0x63, 0x6f, 0x40, 0xaf, 0x74, 0xb8, 0x2d, 0x80, 0xbb, 0x46, 0x94, 0xe5, 0x29, 0xee, 0xb7, 0x1b,
	0x96, 0xad, 0x13, 0x0e, 0x58, 0x99, 0x60, 0x4d, 0x17, 0x26, 0xce, 0xe8, 0xdb, 0xef, 0x24, 0xa3,
	0x6e, 0x7f, 0x54, 0x3f, 0x02, 0xd1, 0x5b, 0x50, 0x56, 0x48, 0xf4, 0xbd, 0x62, 0x47, 0x04, 0xcd,
};

const unsigned char kof2000_type0_t12[256] =
{
	0xf4, 0x28, 0xb4, 0x8f, 0xfa, 0xeb, 0x8e, 0x54, 0x2b, 0x49, 0xd1, 0x76, 0x71, 0x47, 0x8b, 0x57,
	0x92, 0x85, 0x7c, 0xb8, 0x5c, 0x22, 0xf9, 0x26, 0xbc, 0x5b, 0x6d, 0x67, 0xae, 0x5f, 0x6f, 0xf5,
	0x9f, 0x48, 0x66, 0x40, 0x0d, 0x11, 0x4e, 0xb2, 0x6b, 0x35, 0x15, 0x0f, 0x18, 0x25, 0x1d, 0xba,
	0xd3, 0x69, 0x79, 0xec, 0xa8, 0x8c, 0xc9, 0x7f, 0x4b, 0xdb, 0x51, 0xaf, 0xca, 0xe2, 0xb3, 0x81,
	0x12, 0x5e, 0x7e, 0x38, 0xc8, 0x95, 0x01, 0xff, 0xfd, 0xfb, 0xf2, 0x74, 0x62, 0x14, 0xa5, 0x98,
	0xa6, 0xda, 0x80, 0x53, 0xe8, 0x56, 0xac, 0x1b, 0x52, 0xd0, 0xf1, 0x45, 0x42, 0xb6, 0x1a, 0x4a,
	0x3a, 0x99, 0xfc, 0xd2, 0x9c, 0xcf, 0x31, 0x2d, 0xdd, 0x86, 0x2f, 0x29, 0xe1, 0x03, 0x19, 0xa2,
	0x41, 0x33, 0x83, 0x90, 0xc1, 0xbf, 0x0b, 0x08, 0x3d, 0xd8, 0x8d, 0x6c, 0x39, 0xa0, 0xe3, 0x55,
	0x02, 0x50, 0x46, 0xe6, 0xc3, 0x82, 0x36, 0x13, 0x75, 0xab, 0x27, 0xd7, 0x1f, 0x0a, 0xd4, 0x89,
	0x59, 0x4f, 0xc0, 0x5d, 0xc6, 0xf7, 0x88, 0xbd, 0x3c, 0x00, 0xef, 0xcd, 0x05, 0x1c, 0xaa, 0x9b,
	0xed, 0x7a, 0x61, 0x17, 0x93, 0xfe, 0x23, 0xb9, 0xf3, 0x68, 0x78, 0xf6, 0x5a, 0x7b, 0xe0, 0xe4,
	0xa3, 0xee, 0x16, 0x72, 0xc7, 0x3b, 0x8a, 0x37, 0x2a, 0x70, 0xa9, 0x2c, 0x21, 0xf8, 0x24, 0x09,
	0xce, 0x20, 0x9e, 0x06, 0x87, 0xc5, 0x04, 0x64, 0x43, 0x7d, 0x4d, 0x10, 0xd6, 0xa4, 0x94, 0x4c,
	0x60, 0xde, 0xdf, 0x58, 0xb1, 0x44, 0x3f, 0xb0, 0xd9, 0xe5, 0xcb, 0xbb, 0xbe, 0xea, 0x07, 0x34,
	0x73, 0x6a, 0x77, 0xf0, 0x9d, 0x0c, 0x2e, 0x0e, 0x91, 0x9a, 0xcc, 0xc2, 0xb7, 0x63, 0x97, 0xd5,
	0xdc, 0xc4, 0x32, 0xe7, 0x84, 0x3e, 0x30, 0xa1, 0x1e, 0xb5, 0x6e, 0x65, 0xe9, 0xad, 0xa7, 0x96,
};

const unsigned char kof2000_type1_t03[256] =
{
	0x9a, 0x2f, 0xcc, 0x4e, 0x40, 0x69, 0xac, 0xca, 0xa5, 0x7b, 0x0a, 0x61, 0x91, 0x0d, 0x55, 0x74,
	0xcd, 0x8b, 0x0b, 0x80, 0x09, 0x5e, 0x38, 0xc7, 0xda, 0xbf, 0xf5, 0x37, 0x23, 0x31, 0x33, 0xe9,
	0xae, 0x87, 0xe5, 0xfa, 0x6e, 0x5c, 0xad, 0xf4, 0x76, 0x62, 0x9f, 0x2e, 0x01, 0xe2, 0xf6, 0x47,
	0x8c, 0x7c, 0xaa, 0x98, 0xb5, 0x92, 0x51, 0xec, 0x5f, 0x07, 0x5d, 0x6f, 0x16, 0xa1, 0x1d, 0xa9,
	0x48, 0x45, 0xf0, 0x6a, 0x9c, 0x1e, 0x11, 0xa0, 0x06, 0x46, 0xd5, 0xf1, 0x73, 0xed, 0x94, 0xf7,
	0xc3, 0x57, 0x1b, 0xe0, 0x97, 0xb1, 0xa4, 0xa7, 0x24, 0xe7, 0x2b, 0x05, 0x5b, 0x34, 0x0c, 0xb8,
	0x0f, 0x9b, 0xc8, 0x4d, 0x5a, 0xa6, 0x86, 0x3e, 0x14, 0x29, 0x84, 0x58, 0x90, 0xdb, 0x2d, 0x54,
	0x9d, 0x82, 0xd4, 0x7d, 0xc6, 0x67, 0x41, 0x89, 0xc1, 0x13, 0xb0, 0x9e, 0x81, 0x6d, 0xa8, 0x59,
	0xbd, 0x39, 0x8e, 0xe6, 0x25, 0x8f, 0xd9, 0xa2, 0xe4, 0x53, 0xc5, 0x72, 0x7e, 0x36, 0x4a, 0x4f,
	0x52, 0xc2, 0x22, 0x2a, 0xce, 0x3c, 0x21, 0x2c, 0x00, 0xd7, 0x75, 0x8a, 0x27, 0xee, 0x43, 0xfe,
	0xcb, 0x6b, 0xb9, 0xa3, 0x78, 0xb7, 0x85, 0x02, 0x20, 0xd0, 0x83, 0xc4, 0x12, 0xf9, 0xfd, 0xd8,
	0x79, 0x64, 0x3a, 0x49, 0x03, 0xb4, 0xc0, 0xf2, 0xdf, 0x15, 0x93, 0x08, 0x35, 0xff, 0x70, 0xdd,
	0x28, 0x6c, 0x0e, 0x04, 0xde, 0x7a, 0x65, 0xd2, 0xab, 0x42, 0x95, 0xe1, 0x3f, 0x3b, 0x7f, 0x66,
	0xd1, 0x8d, 0xe3, 0xbb, 0x1c, 0xfc, 0x77, 0x1a, 0x88, 0x18, 0x19, 0x68, 0x1f, 0x56, 0xd6, 0xe8,
	0xb6, 0xbc, 0xd3, 0xea, 0x3d, 0x26, 0xb3, 0xc9, 0x44, 0xdc, 0xf3, 0x32, 0x30, 0xef, 0x96, 0x4c,
	0xaf, 0x17, 0xf8, 0xfb, 0x60, 0x50, 0xeb, 0x4b, 0x99, 0x63, 0xba, 0xb2, 0x71, 0xcf, 0x10, 0xbe,
};

const unsigned char kof2000_type1_t12[256] =
{
	0xda, 0xa7, 0xd6, 0x6e, 0x2f, 0x5e, 0xf0, 0x3f, 0xa4, 0xce, 0xd3, 0xfd, 0x46, 0x2a, 0xac, 0xc9,
	0xbe, 0xeb, 0x9f, 0xd5, 0x3c, 0x61, 0x96, 0x11, 0xd0, 0x38, 0xca, 0x06, 0xed, 0x1b, 0x65, 0xe7,
	0x23, 0xdd, 0xd9, 0x05, 0xbf, 0x5b, 0x5d, 0xa5, 0x95, 0x00, 0xec, 0xf1, 0x01, 0xa9, 0xa6, 0xfc,
	0xbb, 0x54, 0xe3, 0x2e, 0x92, 0x58, 0x0a, 0x7b, 0xb6, 0xcc, 0xb1, 0x5f, 0x14, 0x35, 0x72, 0xff,
	0xe6, 0x52, 0xd7, 0x8c, 0xf3, 0x43, 0xaf, 0x9c, 0xc0, 0x4f, 0x0c, 0x42, 0x8e, 0xef, 0x80, 0xcd,
	0x1d, 0x7e, 0x88, 0x3b, 0x98, 0xa1, 0xad, 0xe4, 0x9d, 0x8d, 0x2b, 0x56, 0xb5, 0x50, 0xdf, 0x66,
	0x6d, 0xd4, 0x60, 0x09, 0xe1, 0xee, 0x4a, 0x47, 0xf9, 0xfe, 0x73, 0x07, 0x89, 0xa8, 0x39, 0xea,
	0x82, 0x9e, 0xcf, 0x26, 0xb2, 0x4e, 0xc3, 0x59, 0xf2, 0x3d, 0x9a, 0xb0, 0x69, 0xf7, 0xbc, 0x34,
	0xe5, 0x36, 0x22, 0xfb, 0x57, 0x71, 0x99, 0x6c, 0x83, 0x30, 0x55, 0xc2, 0xbd, 0xf4, 0x77, 0xe9,
	0x76, 0x97, 0xa0, 0xe0, 0xb9, 0x86, 0x6b, 0xa3, 0x84, 0x67, 0x1a, 0x70, 0x02, 0x5a, 0x41, 0x5c,
	0x25, 0x81, 0xaa, 0x28, 0x78, 0x4b, 0xc6, 0x64, 0x53, 0x16, 0x4d, 0x8b, 0x20, 0x93, 0xae, 0x0f,
	0x94, 0x2c, 0x3a, 0xc7, 0x62, 0xe8, 0xc4, 0xdb, 0x04, 0xc5, 0xfa, 0x29, 0x48, 0xd1, 0x08, 0x24,
	0x0d, 0xe2, 0xd8, 0x10, 0xb4, 0x91, 0x8a, 0x13, 0x0e, 0xdc, 0xd2, 0x79, 0xb8, 0xf8, 0xba, 0x2d,
	0xcb, 0xf5, 0x7d, 0x37, 0x51, 0x40, 0x31, 0xa2, 0x0b, 0x18, 0x63, 0x7f, 0xb3, 0xab, 0x9b, 0x87,
	0xf6, 0x90, 0xde, 0xc8, 0x27, 0x45, 0x7c, 0x1c, 0x85, 0x68, 0x33, 0x19, 0x03, 0x75, 0x15, 0x7a,
	0x1f, 0x49, 0x8f, 0x4c, 0xc1, 0x44, 0x17, 0x12, 0x6f, 0x32, 0xb7, 0x3e, 0x74, 0x1e, 0x21, 0x6a,
};



const unsigned char kof2000_address_8_15_xor1[256] =
{
	0xfc, 0x9b, 0x1c, 0x35, 0x72, 0x53, 0xd6, 0x7d, 0x84, 0xa4, 0xc5, 0x93, 0x7b, 0xe7, 0x47, 0xd5,
	0x24, 0xa2, 0xfa, 0x19, 0x0c, 0xb1, 0x8c, 0xb9, 0x9d, 0xd8, 0x59, 0x4f, 0x3c, 0xb2, 0x78, 0x4a,
	0x2a, 0x96, 0x9a, 0xf1, 0x1f, 0x22, 0xa8, 0x5b, 0x67, 0xa3, 0x0f, 0x00, 0xfb, 0xdf, 0xeb, 0x0a,
	0x57, 0xb8, 0x25, 0xd7, 0xf0, 0x6b, 0x0b, 0x31, 0x95, 0x23, 0x2d, 0x5c, 0x27, 0xc7, 0xf4, 0x55,
	0x1a, 0xf7, 0x74, 0xbe, 0xd3, 0xac, 0x3d, 0xc1, 0x7f, 0xbd, 0x28, 0x01, 0x10, 0xe5, 0x09, 0x37,
	0x1e, 0x58, 0xaf, 0x17, 0xf2, 0x16, 0x30, 0x92, 0x36, 0x68, 0xe6, 0xd4, 0xea, 0xb7, 0x75, 0x54,
	0x77, 0x41, 0xb4, 0x8d, 0xe0, 0xf3, 0x51, 0x03, 0xa9, 0xe8, 0x66, 0xab, 0x29, 0xa5, 0xed, 0xcb,
	0xd1, 0xaa, 0xf5, 0xdb, 0x4c, 0x42, 0x97, 0x8a, 0xae, 0xc9, 0x6e, 0x04, 0x33, 0x85, 0xdd, 0x2b,
	0x6f, 0xef, 0x12, 0x21, 0x7a, 0xa1, 0x5a, 0x91, 0xc8, 0xcc, 0xc0, 0xa7, 0x60, 0x3e, 0x56, 0x2f,
	0xe4, 0x71, 0x99, 0xc2, 0xa0, 0x45, 0x80, 0x65, 0xbb, 0x87, 0x69, 0x81, 0x73, 0xca, 0xf6, 0x46,
	0x43, 0xda, 0x26, 0x7e, 0x8f, 0xe1, 0x8b, 0xfd, 0x50, 0x79, 0xba, 0xc6, 0x63, 0x4b, 0xb3, 0x8e,
	0x34, 0xe2, 0x48, 0x14, 0xcd, 0xe3, 0xc4, 0x05, 0x13, 0x40, 0x06, 0x6c, 0x88, 0xb0, 0xe9, 0x1b,
	0x4d, 0xf8, 0x76, 0x02, 0x44, 0x94, 0xcf, 0x32, 0xfe, 0xce, 0x3b, 0x5d, 0x2c, 0x89, 0x5f, 0xdc,
	0xd2, 0x9c, 0x6a, 0xec, 0x18, 0x6d, 0x0e, 0x86, 0xff, 0x5e, 0x9e, 0xee, 0x11, 0xd0, 0x49, 0x52,
	0x4e, 0x61, 0x90, 0x0d, 0xc3, 0x39, 0x15, 0x83, 0xb5, 0x62, 0x3f, 0x70, 0x7c, 0xad, 0x20, 0xbf,
	0x2e, 0x08, 0x1d, 0xf9, 0xb6, 0xa6, 0x64, 0x07, 0x82, 0x38, 0x98, 0x3a, 0x9f, 0xde, 0xbc, 0xd9,
};

const unsigned char kof2000_address_8_15_xor2[256] =
{
	0x00, 0xbe, 0x06, 0x5a, 0xfa, 0x42, 0x15, 0xf2, 0x3f, 0x0a, 0x84, 0x93, 0x4e, 0x78, 0x3b, 0x89,
	0x32, 0x98, 0xa2, 0x87, 0x73, 0xdd, 0x26, 0xe5, 0x05, 0x71, 0x08, 0x6e, 0x9b, 0xe0, 0xdf, 0x9e,
	0xfc, 0x83, 0x81, 0xef, 0xb2, 0xc0, 0xc3, 0xbf, 0xa7, 0x6d, 0x1b, 0x95, 0xed, 0xb9, 0x3e, 0x13,
	0xb0, 0x47, 0x9c, 0x7a, 0x24, 0x41, 0x68, 0xd0, 0x36, 0x0b, 0xb5, 0xc2, 0x67, 0xf7, 0x54, 0x92,
	0x1e, 0x44, 0x86, 0x2b, 0x94, 0xcc, 0xba, 0x23, 0x0d, 0xca, 0x6b, 0x4c, 0x2a, 0x9a, 0x2d, 0x8b,
	0xe3, 0x52, 0x29, 0xf0, 0x21, 0xbd, 0xbb, 0x1f, 0xa3, 0xab, 0xf8, 0x46, 0xb7, 0x45, 0x82, 0x5e,
	0xdb, 0x07, 0x5d, 0xe9, 0x9d, 0x1a, 0x48, 0xce, 0x91, 0x12, 0xd4, 0xee, 0xa9, 0x39, 0xf1, 0x18,
	0x2c, 0x22, 0x8a, 0x7e, 0x34, 0x4a, 0x8c, 0xc1, 0x14, 0xf3, 0x20, 0x35, 0xd9, 0x96, 0x33, 0x77,
	0x9f, 0x76, 0x7c, 0x90, 0xc6, 0xd5, 0xa1, 0x5b, 0xac, 0x75, 0xc7, 0x0c, 0xb3, 0x17, 0xd6, 0x99,
	0x56, 0xa6, 0x3d, 0x1d, 0xb1, 0x2e, 0xd8, 0xbc, 0x2f, 0xde, 0x60, 0x55, 0x6c, 0x40, 0xcd, 0x43,
	0xff, 0xad, 0x38, 0x79, 0x51, 0xc8, 0x0e, 0x5f, 0xc4, 0x66, 0xcb, 0xa8, 0x7d, 0xa4, 0x3a, 0xea,
	0x27, 0x7b, 0x70, 0x8e, 0x5c, 0x19, 0x0f, 0x80, 0x6f, 0x8f, 0x10, 0xf9, 0x49, 0x85, 0x69, 0x7f,
	0xeb, 0x1c, 0x01, 0x65, 0x37, 0xa5, 0x28, 0xe4, 0x6a, 0x03, 0x04, 0xd1, 0x31, 0x11, 0x30, 0xfb,
	0x88, 0x97, 0xd3, 0xf6, 0xc5, 0x4d, 0xf5, 0x3c, 0xe8, 0x61, 0xdc, 0xd2, 0xb4, 0xb8, 0xa0, 0xae,
	0x16, 0x25, 0x02, 0x09, 0xfe, 0xcf, 0x53, 0x63, 0xaf, 0x59, 0xf4, 0xe1, 0xec, 0xd7, 0xe7, 0x50,
	0xe2, 0xc9, 0xaa, 0x4b, 0x8d, 0x4f, 0xe6, 0x64, 0xda, 0x74, 0xb6, 0x72, 0x57, 0x62, 0xfd, 0x58,
};

const unsigned char kof2000_address_16_23_xor1[256] =
{
	0x45, 0x9f, 0x6e, 0x2f, 0x28, 0xbc, 0x5e, 0x6d, 0xda, 0xb5, 0x0d, 0xb8, 0xc0, 0x8e, 0xa2, 0x32,
	0xee, 0xcd, 0x8d, 0x48, 0x8c, 0x27, 0x14, 0xeb, 0x65, 0xd7, 0xf2, 0x93, 0x99, 0x90, 0x91, 0xfc,
	0x5f, 0xcb, 0xfa, 0x75, 0x3f, 0x26, 0xde, 0x72, 0x33, 0x39, 0xc7, 0x1f, 0x88, 0x79, 0x73, 0xab,
	0x4e, 0x36, 0x5d, 0x44, 0xd2, 0x41, 0xa0, 0x7e, 0xa7, 0x8b, 0xa6, 0xbf, 0x03, 0xd8, 0x86, 0xdc,
	0x2c, 0xaa, 0x70, 0x3d, 0x46, 0x07, 0x80, 0x58, 0x0b, 0x2b, 0xe2, 0xf0, 0xb1, 0xfe, 0x42, 0xf3,
	0xe9, 0xa3, 0x85, 0x78, 0xc3, 0xd0, 0x5a, 0xdb, 0x1a, 0xfb, 0x9d, 0x8a, 0xa5, 0x12, 0x0e, 0x54,
	0x8f, 0xc5, 0x6c, 0xae, 0x25, 0x5b, 0x4b, 0x17, 0x02, 0x9c, 0x4a, 0x24, 0x40, 0xe5, 0x9e, 0x22,
	0xc6, 0x49, 0x62, 0xb6, 0x6b, 0xbb, 0xa8, 0xcc, 0xe8, 0x81, 0x50, 0x47, 0xc8, 0xbe, 0x5c, 0xa4,
	0xd6, 0x94, 0x4f, 0x7b, 0x9a, 0xcf, 0xe4, 0x59, 0x7a, 0xa1, 0xea, 0x31, 0x37, 0x13, 0x2d, 0xaf,
	0x21, 0x69, 0x19, 0x1d, 0x6f, 0x16, 0x98, 0x1e, 0x08, 0xe3, 0xb2, 0x4d, 0x9b, 0x7f, 0xa9, 0x77,
	0xed, 0xbd, 0xd4, 0xd9, 0x34, 0xd3, 0xca, 0x09, 0x18, 0x60, 0xc9, 0x6a, 0x01, 0xf4, 0xf6, 0x64,
	0xb4, 0x3a, 0x15, 0xac, 0x89, 0x52, 0x68, 0x71, 0xe7, 0x82, 0xc1, 0x0c, 0x92, 0xf7, 0x30, 0xe6,
	0x1c, 0x3e, 0x0f, 0x0a, 0x67, 0x35, 0xba, 0x61, 0xdd, 0x29, 0xc2, 0xf8, 0x97, 0x95, 0xb7, 0x3b,
	0xe0, 0xce, 0xf9, 0xd5, 0x06, 0x76, 0xb3, 0x05, 0x4c, 0x04, 0x84, 0x3c, 0x87, 0x23, 0x63, 0x7c,
	0x53, 0x56, 0xe1, 0x7d, 0x96, 0x1b, 0xd1, 0xec, 0x2a, 0x66, 0xf1, 0x11, 0x10, 0xff, 0x43, 0x2e,
	0xdf, 0x83, 0x74, 0xf5, 0x38, 0x20, 0xfd, 0xad, 0xc4, 0xb9, 0x55, 0x51, 0xb0, 0xef, 0x00, 0x57,
};

const unsigned char kof2000_address_16_23_xor2[256] =
{
	0x00, 0xb8, 0xf0, 0x34, 0xca, 0x21, 0x3c, 0xf9, 0x01, 0x8e, 0x75, 0x70, 0xec, 0x13, 0x27, 0x96,
	0xf4, 0x5b, 0x88, 0x1f, 0xeb, 0x4a, 0x7d, 0x9d, 0xbe, 0x02, 0x14, 0xaf, 0xa2, 0x06, 0xc6, 0xdb,
	0x35, 0x6b, 0x74, 0x45, 0x7b, 0x29, 0xd2, 0xfe, 0xb6, 0x15, 0xd0, 0x8a, 0xa9, 0x2d, 0x19, 0xf6,
	0x5e, 0x5a, 0x90, 0xe9, 0x11, 0x33, 0xc2, 0x47, 0x37, 0x4c, 0x4f, 0x59, 0xc3, 0x04, 0x57, 0x1d,
	0xf2, 0x63, 0x6d, 0x6e, 0x31, 0x95, 0xcb, 0x3e, 0x67, 0xb2, 0xe3, 0x98, 0xed, 0x8d, 0xe6, 0xfb,
	0xf8, 0xba, 0x5d, 0xd4, 0x2a, 0xf5, 0x3b, 0x82, 0x05, 0x16, 0x44, 0xef, 0x4d, 0xe7, 0x93, 0xda,
	0x9f, 0xbb, 0x61, 0xc9, 0x53, 0xbd, 0x76, 0x78, 0x52, 0x36, 0x0c, 0x66, 0xc1, 0x10, 0xdd, 0x7a,
	0x84, 0x69, 0xcd, 0xfd, 0x58, 0x0d, 0x6c, 0x89, 0x68, 0xad, 0x3a, 0xb0, 0x4b, 0x46, 0xc5, 0x03,
	0xb4, 0xf7, 0x30, 0x8c, 0x4e, 0x60, 0x73, 0xa1, 0x8b, 0xb1, 0x62, 0xcc, 0xd1, 0x08, 0xfc, 0x77,
	0x7e, 0xcf, 0x56, 0x51, 0x07, 0xa6, 0x80, 0x92, 0xdc, 0x0b, 0xa4, 0xc7, 0xe8, 0xe1, 0xb5, 0x71,
	0xea, 0xb3, 0x2f, 0x94, 0x18, 0xe2, 0x3d, 0x49, 0x65, 0xaa, 0xf1, 0x91, 0xc8, 0x99, 0x55, 0x79,
	0x86, 0xa7, 0x26, 0xa0, 0xac, 0x5f, 0xce, 0x6a, 0x5c, 0xf3, 0x87, 0x8f, 0x12, 0x1c, 0xd8, 0xe4,
	0x9b, 0x64, 0x2e, 0x1e, 0xd7, 0xc0, 0x17, 0xbc, 0xa3, 0xa8, 0x9a, 0x0e, 0x25, 0x40, 0x41, 0x50,
	0xb9, 0xbf, 0x28, 0xdf, 0x32, 0x54, 0x9e, 0x48, 0xd5, 0x2b, 0x42, 0xfa, 0x9c, 0x7f, 0xd3, 0x85,
	0x43, 0xde, 0x81, 0x0f, 0x24, 0xc4, 0x38, 0xae, 0x83, 0x1b, 0x6f, 0x7c, 0xe5, 0xff, 0x1a, 0xd9,
	0x3f, 0xb7, 0x22, 0x97, 0x09, 0xe0, 0xa5, 0x20, 0x23, 0x2c, 0x72, 0xd6, 0x39, 0xab, 0x0a, 0xee,
};

const unsigned char kof2000_address_0_7_xor[256] =
{
	0x26, 0x48, 0x06, 0x9b, 0x21, 0xa9, 0x1b, 0x76, 0xc9, 0xf8, 0xb4, 0x67, 0xe4, 0xff, 0x99, 0xf7,
	0x15, 0x9e, 0x62, 0x00, 0x72, 0x4d, 0xa0, 0x4f, 0x02, 0xf1, 0xea, 0xef, 0x0b, 0xf3, 0xeb, 0xa6,
	0x93, 0x78, 0x6f, 0x7c, 0xda, 0xd4, 0x7b, 0x05, 0xe9, 0xc6, 0xd6, 0xdb, 0x50, 0xce, 0xd2, 0x01,
	0xb5, 0xe8, 0xe0, 0x2a, 0x08, 0x1a, 0xb8, 0xe3, 0xf9, 0xb1, 0xf4, 0x8b, 0x39, 0x2d, 0x85, 0x9c,
	0x55, 0x73, 0x63, 0x40, 0x38, 0x96, 0xdc, 0xa3, 0xa2, 0xa1, 0x25, 0x66, 0x6d, 0x56, 0x8e, 0x10,
	0x0f, 0x31, 0x1c, 0xf5, 0x28, 0x77, 0x0a, 0xd1, 0x75, 0x34, 0xa4, 0xfe, 0x7d, 0x07, 0x51, 0x79,
	0x41, 0x90, 0x22, 0x35, 0x12, 0xbb, 0xc4, 0xca, 0xb2, 0x1f, 0xcb, 0xc8, 0xac, 0xdd, 0xd0, 0x0d,
	0xfc, 0xc5, 0x9d, 0x14, 0xbc, 0x83, 0xd9, 0x58, 0xc2, 0x30, 0x9a, 0x6a, 0xc0, 0x0c, 0xad, 0xf6,
	0x5d, 0x74, 0x7f, 0x2f, 0xbd, 0x1d, 0x47, 0xd5, 0xe6, 0x89, 0xcf, 0xb7, 0xd3, 0x59, 0x36, 0x98,
	0xf0, 0xfb, 0x3c, 0xf2, 0x3f, 0xa7, 0x18, 0x82, 0x42, 0x5c, 0xab, 0xba, 0xde, 0x52, 0x09, 0x91,
	0xaa, 0x61, 0xec, 0xd7, 0x95, 0x23, 0xcd, 0x80, 0xa5, 0x68, 0x60, 0x27, 0x71, 0xe1, 0x2c, 0x2e,
	0x8d, 0x2b, 0x57, 0x65, 0xbf, 0xc1, 0x19, 0xc7, 0x49, 0x64, 0x88, 0x4a, 0xcc, 0x20, 0x4e, 0xd8,
	0x3b, 0x4c, 0x13, 0x5f, 0x9f, 0xbe, 0x5e, 0x6e, 0xfd, 0xe2, 0xfa, 0x54, 0x37, 0x0e, 0x16, 0x7a,
	0x6c, 0x33, 0xb3, 0x70, 0x84, 0x7e, 0xc3, 0x04, 0xb0, 0xae, 0xb9, 0x81, 0x03, 0x29, 0xdf, 0x46,
	0xe5, 0x69, 0xe7, 0x24, 0x92, 0x5a, 0x4b, 0x5b, 0x94, 0x11, 0x3a, 0x3d, 0x87, 0xed, 0x97, 0xb6,
	0x32, 0x3e, 0x45, 0xaf, 0x1e, 0x43, 0x44, 0x8c, 0x53, 0x86, 0x6b, 0xee, 0xa8, 0x8a, 0x8f, 0x17,
};

static const UINT8 m1_address_8_15_xor[256] =
{
        0x0a, 0x72, 0xb7, 0xaf, 0x67, 0xde, 0x1d, 0xb1, 0x78, 0xc4, 0x4f, 0xb5, 0x4b, 0x18, 0x76, 0xdd,
        0x11, 0xe2, 0x36, 0xa1, 0x82, 0x03, 0x98, 0xa0, 0x10, 0x5f, 0x3f, 0xd6, 0x1f, 0x90, 0x6a, 0x0b,
        0x70, 0xe0, 0x64, 0xcb, 0x9f, 0x38, 0x8b, 0x53, 0x04, 0xca, 0xf8, 0xd0, 0x07, 0x68, 0x56, 0x32,
        0xae, 0x1c, 0x2e, 0x48, 0x63, 0x92, 0x9a, 0x9c, 0x44, 0x85, 0x41, 0x40, 0x09, 0xc0, 0xc8, 0xbf,
        0xea, 0xbb, 0xf7, 0x2d, 0x99, 0x21, 0xf6, 0xba, 0x15, 0xce, 0xab, 0xb0, 0x2a, 0x60, 0xbc, 0xf1,
        0xf0, 0x9e, 0xd5, 0x97, 0xd8, 0x4e, 0x14, 0x9d, 0x42, 0x4d, 0x2c, 0x5c, 0x2b, 0xa6, 0xe1, 0xa7,
        0xef, 0x25, 0x33, 0x7a, 0xeb, 0xe7, 0x1b, 0x6d, 0x4c, 0x52, 0x26, 0x62, 0xb6, 0x35, 0xbe, 0x80,
        0x01, 0xbd, 0xfd, 0x37, 0xf9, 0x47, 0x55, 0x71, 0xb4, 0xf2, 0xff, 0x27, 0xfa, 0x23, 0xc9, 0x83,
        0x17, 0x39, 0x13, 0x0d, 0xc7, 0x86, 0x16, 0xec, 0x49, 0x6f, 0xfe, 0x34, 0x05, 0x8f, 0x00, 0xe6,
        0xa4, 0xda, 0x7b, 0xc1, 0xf3, 0xf4, 0xd9, 0x75, 0x28, 0x66, 0x87, 0xa8, 0x45, 0x6c, 0x20, 0xe9,
        0x77, 0x93, 0x7e, 0x3c, 0x1e, 0x74, 0xf5, 0x8c, 0x3e, 0x94, 0xd4, 0xc2, 0x5a, 0x06, 0x0e, 0xe8,
        0x3d, 0xa9, 0xb2, 0xe3, 0xe4, 0x22, 0xcf, 0x24, 0x8e, 0x6b, 0x8a, 0x8d, 0x84, 0x4a, 0xd2, 0x91,
        0x88, 0x79, 0x57, 0xa5, 0x0f, 0xcd, 0xb9, 0xac, 0x3b, 0xaa, 0xb3, 0xd1, 0xee, 0x31, 0x81, 0x7c,
        0xd7, 0x89, 0xd3, 0x96, 0x43, 0xc5, 0xc6, 0xc3, 0x69, 0x7f, 0x46, 0xdf, 0x30, 0x5b, 0x6e, 0xe5,
        0x08, 0x95, 0x9b, 0xfb, 0xb8, 0x58, 0x0c, 0x61, 0x50, 0x5d, 0x3a, 0xa2, 0x29, 0x12, 0xfc, 0x51,
        0x7d, 0x1a, 0x02, 0x65, 0x54, 0x5e, 0x19, 0xcc, 0xdc, 0xdb, 0x73, 0xed, 0xad, 0x59, 0x2f, 0xa3,
};

static const UINT8 m1_address_0_7_xor[256] =
{
        0xf4, 0xbc, 0x02, 0xf7, 0x2c, 0x3d, 0xe8, 0xd9, 0x50, 0x62, 0xec, 0xbd, 0x53, 0x73, 0x79, 0x61,
        0x00, 0x34, 0xcf, 0xa2, 0x63, 0x28, 0x90, 0xaf, 0x44, 0x3b, 0xc5, 0x8d, 0x3a, 0x46, 0x07, 0x70,
        0x66, 0xbe, 0xd8, 0x8b, 0xe9, 0xa0, 0x4b, 0x98, 0xdc, 0xdf, 0xe2, 0x16, 0x74, 0xf1, 0x37, 0xf5,
        0xb7, 0x21, 0x81, 0x01, 0x1c, 0x1b, 0x94, 0x36, 0x09, 0xa1, 0x4a, 0x91, 0x30, 0x92, 0x9b, 0x9a,
        0x29, 0xb1, 0x38, 0x4d, 0x55, 0xf2, 0x56, 0x18, 0x24, 0x47, 0x9d, 0x3f, 0x80, 0x1f, 0x22, 0xa4,
        0x11, 0x54, 0x84, 0x0d, 0x25, 0x48, 0xee, 0xc6, 0x59, 0x15, 0x03, 0x7a, 0xfd, 0x6c, 0xc3, 0x33,
        0x5b, 0xc4, 0x7b, 0x5a, 0x05, 0x7f, 0xa6, 0x40, 0xa9, 0x5d, 0x41, 0x8a, 0x96, 0x52, 0xd3, 0xf0,
        0xab, 0x72, 0x10, 0x88, 0x6f, 0x95, 0x7c, 0xa8, 0xcd, 0x9c, 0x5f, 0x32, 0xae, 0x85, 0x39, 0xac,
        0xe5, 0xd7, 0xfb, 0xd4, 0x08, 0x23, 0x19, 0x65, 0x6b, 0xa7, 0x93, 0xbb, 0x2b, 0xbf, 0xb8, 0x35,
        0xd0, 0x06, 0x26, 0x68, 0x3e, 0xdd, 0xb9, 0x69, 0x2a, 0xb2, 0xde, 0x87, 0x45, 0x58, 0xff, 0x3c,
        0x9e, 0x7d, 0xda, 0xed, 0x49, 0x8c, 0x14, 0x8e, 0x75, 0x2f, 0xe0, 0x6e, 0x78, 0x6d, 0x20, 0xd2,
        0xfa, 0x2d, 0x51, 0xcc, 0xc7, 0xe7, 0x1d, 0x27, 0x97, 0xfc, 0x31, 0xdb, 0xf8, 0x42, 0xe3, 0x99,
        0x5e, 0x83, 0x0e, 0xb4, 0x2e, 0xf6, 0xc0, 0x0c, 0x4c, 0x57, 0xb6, 0x64, 0x0a, 0x17, 0xa3, 0xc1,
        0x77, 0x12, 0xfe, 0xe6, 0x8f, 0x13, 0x71, 0xe4, 0xf9, 0xad, 0x9f, 0xce, 0xd5, 0x89, 0x7e, 0x0f,
        0xc2, 0x86, 0xf3, 0x67, 0xba, 0x60, 0x43, 0xc9, 0x04, 0xb3, 0xb0, 0x1e, 0xb5, 0xc8, 0xeb, 0xa5,
        0x76, 0xea, 0x5c, 0x82, 0x1a, 0x4f, 0xaa, 0xca, 0xe1, 0x0b, 0x4e, 0xcb, 0x6a, 0xef, 0xd1, 0xd6,
};




static void decrypt(unsigned char *r0, unsigned char *r1,
		    unsigned char c0,  unsigned char c1,
		    const unsigned char *table0hi,
		    const unsigned char *table0lo,
		    const unsigned char *table1,
		    int base,
		    int invert)

{
	unsigned char tmp,xor0,xor1;

	tmp = table1[(base & 0xff) ^ address_0_7_xor[(base >> 8) & 0xff]];
	xor0 = (table0hi[(base >> 8) & 0xff] & 0xfe) | (tmp & 0x01);
	xor1 = (tmp & 0xfe) | (table0lo[(base >> 8) & 0xff] & 0x01);

	if (invert)
	{
		*r0 = c1 ^ xor0;
		*r1 = c0 ^ xor1;
	}
	else
	{
		*r0 = c0 ^ xor0;
		*r1 = c1 ^ xor1;
	}
}

static void neogeo_gfx_decrypt(int extra_xor)
{
	int rom_size;
	UINT8 *buf;
	UINT8 *rom;
	int rpos;

	rom_size = memory_region_length(REGION_GFX3);

	buf = malloc(rom_size);

	if (!buf) return;

	rom = memory_region(REGION_GFX3);

	/* Data xor*/
	for (rpos = 0;rpos < rom_size/4;rpos++)
	{
		decrypt(buf+4*rpos+0, buf+4*rpos+3, rom[4*rpos+0], rom[4*rpos+3], type0_t03, type0_t12, type1_t03, rpos, (rpos>>8) & 1);
		decrypt(buf+4*rpos+1, buf+4*rpos+2, rom[4*rpos+1], rom[4*rpos+2], type0_t12, type0_t03, type1_t12, rpos, ((rpos>>16) ^ address_16_23_xor2[(rpos>>8) & 0xff]) & 1);
	}

	/* Address xor*/
	for (rpos = 0;rpos < rom_size/4;rpos++)
	{
		int baser;

		baser = rpos;

		baser ^= extra_xor;

		baser ^= address_8_15_xor1[(baser >> 16) & 0xff] << 8;
		baser ^= address_8_15_xor2[baser & 0xff] << 8;
		baser ^= address_16_23_xor1[baser & 0xff] << 16;
		baser ^= address_16_23_xor2[(baser >> 8) & 0xff] << 16;
		baser ^= address_0_7_xor[(baser >> 8) & 0xff];

		/* special handling for preisle2 */
		if (rom_size == 0x3000000)
		{
			if (rpos < 0x2000000/4)
				baser &= (0x2000000/4)-1;
			else
				baser = 0x2000000/4 + (baser & ((0x1000000/4)-1));
		}
		else	/* Clamp to the real rom size */
			baser &= (rom_size/4)-1;

		rom[4*rpos+0] = buf[4*baser+0];
		rom[4*rpos+1] = buf[4*baser+1];
		rom[4*rpos+2] = buf[4*baser+2];
		rom[4*rpos+3] = buf[4*baser+3];
	}

	free(buf);


	/* the S data comes from the end fo the C data */
	{
		int i;
		int tx_size = memory_region_length(REGION_GFX1);
		UINT8 *src = memory_region(REGION_GFX3)+rom_size-tx_size;
		UINT8 *dst = memory_region(REGION_GFX1);

		for (i = 0;i < tx_size;i++)
			dst[i] = src[(i & ~0x1f) + ((i & 7) << 2) + ((~i & 8) >> 2) + ((i & 0x10) >> 4)];
	}
}

static void neogeo_gfx_decrypt_for_mc50(int extra_xor)
{
	int rom_size;
	UINT8 *buf;
	UINT8 *rom;
	int rpos;

	rom_size = memory_region_length(REGION_GFX3);
	buf = malloc(rom_size);

	if (!buf) return;

	rom = memory_region(REGION_GFX3);

	/* Data xor */
	for (rpos = 0;rpos < rom_size/4;rpos++)
	{
		decrypt(buf+4*rpos+0, buf+4*rpos+3, rom[4*rpos+0], rom[4*rpos+3], type0_t03, type0_t12, type1_t03, rpos, (rpos>>8) & 1);
		decrypt(buf+4*rpos+1, buf+4*rpos+2, rom[4*rpos+1], rom[4*rpos+2], type0_t12, type0_t03, type1_t12, rpos, ((rpos>>16) ^ address_16_23_xor2[(rpos>>8) & 0xff]) & 1);
	}

	/* Address xor */
	for (rpos = 0;rpos < rom_size/4;rpos++)
	{
		int baser;

		baser = rpos;

		baser ^= extra_xor;

		baser ^= address_8_15_xor1[(baser >> 16) & 0xff] << 8;
		baser ^= address_8_15_xor2[baser & 0xff] << 8;
		baser ^= address_16_23_xor1[baser & 0xff] << 16;
		baser ^= address_16_23_xor2[(baser >> 8) & 0xff] << 16;
		baser ^= address_0_7_xor[(baser >> 8) & 0xff];


		if (rom_size == 0x3000000) /* special handling for preisle2 */
		{
			if (rpos < 0x2000000/4)
				baser &= (0x2000000/4)-1;
			else
				baser = 0x2000000/4 + (baser & ((0x1000000/4)-1));
		}
		else if (rom_size == 0x6000000)	/* special handling for kf2k3pcb */
		{
			if (rpos < 0x4000000/4)
				baser &= (0x4000000/4)-1;
			else
				baser = 0x4000000/4 + (baser & ((0x1000000/4)-1));
		}
		else /* Clamp to the real rom size */
			baser &= (rom_size/4)-1;

		rom[4*rpos+0] = buf[4*baser+0];
		rom[4*rpos+1] = buf[4*baser+1];
		rom[4*rpos+2] = buf[4*baser+2];
		rom[4*rpos+3] = buf[4*baser+3];
	}

	free(buf);
}

/* The CMC50 hardware does a checksum of the first 64kb of the M1 rom,
   ,and uses this checksum as the basis of the key with which to decrypt
   the rom */

static UINT16 generate_cs16(UINT8 *rom, int size)
{
    UINT16 cs16;
    int i;
    cs16 = 0x0000;
    for (i=0;i<size;i++ )
    {
        cs16 += rom[i];
    }
    return cs16&0xFFFF;
}


int m1_address_scramble(int address, UINT16 key)
{
	int block;
	int aux;

	const int p1[8][16] = {
		{15,14,10,7,1,2,3,8,0,12,11,13,6,9,5,4},
		{7,1,8,11,15,9,2,3,5,13,4,14,10,0,6,12},
		{8,6,14,3,10,7,15,1,4,0,2,5,13,11,12,9},
		{2,8,15,9,3,4,11,7,13,6,0,10,1,12,14,5},
		{1,13,6,15,14,3,8,10,9,4,7,12,5,2,0,11},
		{11,15,3,4,7,0,9,2,6,14,12,1,8,5,10,13},
		{10,5,13,8,6,15,1,14,11,9,3,0,12,7,4,2},
		{9,3,7,0,2,12,4,11,14,10,5,8,15,13,1,6},
	};

	block = (address>>16)&7;
	aux = address&0xffff;

        aux ^= BITSWAP16(key,12,0,2,4,8,15,7,13,10,1,3,6,11,9,14,5);
	aux = BITSWAP16(aux,
		p1[block][15],p1[block][14],p1[block][13],p1[block][12],
		p1[block][11],p1[block][10],p1[block][9],p1[block][8],
		p1[block][7],p1[block][6],p1[block][5],p1[block][4],
		p1[block][3],p1[block][2],p1[block][1],p1[block][0]);
        aux ^= m1_address_0_7_xor[(aux>>8)&0xff];
	aux ^= m1_address_8_15_xor[aux&0xff]<<8;
	aux = BITSWAP16(aux, 7,15,14,6,5,13,12,4,11,3,10,2,9,1,8,0);

	return (block<<16)|aux;
}

void neogeo_cmc50_m1_decrypt( void )
{
	UINT8* rom = memory_region( audiocrypt );
	size_t rom_size = 0x80000;
	UINT8* rom2 = memory_region( REGION_CPU2 );

	UINT8* buffer = malloc(rom_size);

	UINT32 i;

	UINT16 key=generate_cs16(rom,0x10000);

	/*printf("key %04x\n",key); */

	for (i=0; i<rom_size; i++)
	{
		buffer[i] = rom[m1_address_scramble(i,key)];
	}

	memcpy(rom,buffer,rom_size);

	memcpy(rom2,rom,0x10000);
	memcpy(rom2+0x10000,rom,0x80000);

	

	free( buffer );
}

/* CMC42 protection chip */
void kof99_neogeo_gfx_decrypt(int extra_xor)
{
	type0_t03 =          kof99_type0_t03;
	type0_t12 =          kof99_type0_t12;
	type1_t03 =          kof99_type1_t03;
	type1_t12 =          kof99_type1_t12;
	address_8_15_xor1 =  kof99_address_8_15_xor1;
	address_8_15_xor2 =  kof99_address_8_15_xor2;
	address_16_23_xor1 = kof99_address_16_23_xor1;
	address_16_23_xor2 = kof99_address_16_23_xor2;
	address_0_7_xor =    kof99_address_0_7_xor;
	neogeo_gfx_decrypt(extra_xor);
}

/* CMC50 protection chip */
void kof2000_neogeo_gfx_decrypt(int extra_xor)
{
	type0_t03 =          kof2000_type0_t03;
	type0_t12 =          kof2000_type0_t12;
	type1_t03 =          kof2000_type1_t03;
	type1_t12 =          kof2000_type1_t12;
	address_8_15_xor1 =  kof2000_address_8_15_xor1;
	address_8_15_xor2 =  kof2000_address_8_15_xor2;
	address_16_23_xor1 = kof2000_address_16_23_xor1;
	address_16_23_xor2 = kof2000_address_16_23_xor2;
	address_0_7_xor =    kof2000_address_0_7_xor;
	neogeo_gfx_decrypt(extra_xor);

	/* here I should also decrypt the sound ROM */
}

void cmc50_neogeo_gfx_decrypt(int extra_xor)
{
	type0_t03 =          kof2000_type0_t03;
	type0_t12 =          kof2000_type0_t12;
	type1_t03 =          kof2000_type1_t03;
	type1_t12 =          kof2000_type1_t12;
	address_8_15_xor1 =  kof2000_address_8_15_xor1;
	address_8_15_xor2 =  kof2000_address_8_15_xor2;
	address_16_23_xor1 = kof2000_address_16_23_xor1;
	address_16_23_xor2 = kof2000_address_16_23_xor2;
	address_0_7_xor =    kof2000_address_0_7_xor;
	neogeo_gfx_decrypt_for_mc50(extra_xor);

	/* here I should also decrypt the sound ROM */
}

void neo_pcm2_snk_1999(int value)
{	/* thanks to Elsemi for the NEO-PCM2 info */
	UINT16 *rom = (UINT16 *)memory_region(REGION_SOUND1);
	int size = memory_region_length(REGION_SOUND1);
	int i, j;

	if( rom != NULL )
	{	/* swap address lines on the whole ROMs */
		UINT16 *buffer = malloc((value / 2) * sizeof(UINT16));
		if (!buffer)
			return;

		for( i = 0; i < size / 2; i += ( value / 2 ) )
		{
			memcpy( buffer, &rom[ i ], value );
			for( j = 0; j < (value / 2); j++ )
			{
				rom[ i + j ] = buffer[ j ^ (value/4) ];
			}
		}
		free(buffer);
	}
}

void neo_pcm2_swap(int value)
{
	static const unsigned int addrs[7][2]={
		{0x000000,0xA5000},
		{0xFFCE20,0x01000},
		{0xFE2CF6,0x4E001},
		{0xFFAC28,0xC2000},
		{0xFEB2C0,0x0A000},
		{0xFF14EA,0xA7001},
		{0xFFB440,0x02000}};
	static const UINT8 xordata[7][8]={
		{0xF9,0xE0,0x5D,0xF3,0xEA,0x92,0xBE,0xEF},
		{0xC4,0x83,0xA8,0x5F,0x21,0x27,0x64,0xAF},
		{0xC3,0xFD,0x81,0xAC,0x6D,0xE7,0xBF,0x9E},
		{0xC3,0xFD,0x81,0xAC,0x6D,0xE7,0xBF,0x9E},
		{0xCB,0x29,0x7D,0x43,0xD2,0x3A,0xC2,0xB4},
		{0x4B,0xA4,0x63,0x46,0xF0,0x91,0xEA,0x62},
		{0x4B,0xA4,0x63,0x46,0xF0,0x91,0xEA,0x62}};
	UINT8 *src = memory_region(REGION_SOUND1);
	UINT8 *buf = malloc(0x1000000);
	int i, j, d;

	memcpy(buf,src,0x1000000);
	for (i=0;i<0x1000000;i++)
	{
		j=BITSWAP24(i,23,22,21,20,19,18,17,0,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,16);
		j=j^addrs[value][1];
		d=((i+addrs[value][0])&0xffffff);
		src[j]=buf[d]^xordata[value][j&0x7];
	}
	free(buf);
}





static READ16_HANDLER( prot_9a37_r )
{
	return 0x9a37;
}
/* information about the sma random number generator provided by razoola */
/* this RNG is correct for KOF99, other games might be different */

int neogeo_rng = 0x2345;	/* this is reset in MACHINE_INIT() */

static READ16_HANDLER( sma_random_r )
{
	int old = neogeo_rng;

	int newbit = (
			(neogeo_rng >> 2) ^
			(neogeo_rng >> 3) ^
			(neogeo_rng >> 5) ^
			(neogeo_rng >> 6) ^
			(neogeo_rng >> 7) ^
			(neogeo_rng >>11) ^
			(neogeo_rng >>12) ^
			(neogeo_rng >>15)) & 1;

	neogeo_rng = ((neogeo_rng << 1) | newbit) & 0xffff;

	return old;
}

void kog_px_decrypt( void )
{
	/* the protection chip does some *very* strange things to the rom */
	UINT8 *src = memory_region(REGION_CPU1);
	UINT8 *dst = malloc( 0x600000 );
	UINT16 *rom = (UINT16 *)memory_region(REGION_CPU1);
	int i;
	static const unsigned int sec[] = { 0x3, 0x8, 0x7, 0xC, 0x1, 0xA, 0x6, 0xD };

	for (i = 0; i < 8; i++){
		memcpy (dst + i * 0x20000, src + sec[i] * 0x20000, 0x20000);
	}

	memcpy (dst + 0x0007A6, src + 0x0407A6, 0x000006);
	memcpy (dst + 0x0007C6, src + 0x0407C6, 0x000006);
	memcpy (dst + 0x0007E6, src + 0x0407E6, 0x000006);
	memcpy (dst + 0x090000, src + 0x040000, 0x004000);
	memcpy (dst + 0x100000, src + 0x200000, 0x400000);
	memcpy (src, dst, 0x600000);
	free (dst);

	for (i = 0x90000/2; i < 0x94000/2; i++){
		if (((rom[i]&0xFFBF) == 0x4EB9 || rom[i] == 0x43F9) && !rom[i + 1])
			rom[i + 1] = 0x0009;

		if (rom[i] == 0x4EB8)
			rom[i] = 0x6100;
	}

	rom[0x007A8/2] = 0x0009;
	rom[0x007C8/2] = 0x0009;
	rom[0x007E8/2] = 0x0009;
	rom[0x93408/2] = 0xF168;
	rom[0x9340C/2] = 0xFB7A;
	rom[0x924AC/2] = 0x0009;
	rom[0x9251C/2] = 0x0009;
	rom[0x93966/2] = 0xFFDA;
	rom[0x93974/2] = 0xFFCC;
	rom[0x93982/2] = 0xFFBE;
	rom[0x93990/2] = 0xFFB0;
	rom[0x9399E/2] = 0xFFA2;
	rom[0x939AC/2] = 0xFF94;
	rom[0x939BA/2] = 0xFF86;
	rom[0x939C8/2] = 0xFF78;
	rom[0x939D4/2] = 0xFA5C;
	rom[0x939E0/2] = 0xFA50;
	rom[0x939EC/2] = 0xFA44;
	rom[0x939F8/2] = 0xFA38;
	rom[0x93A04/2] = 0xFA2C;
	rom[0x93A10/2] = 0xFA20;
	rom[0x93A1C/2] = 0xFA14;
	rom[0x93A28/2] = 0xFA08;
	rom[0x93A34/2] = 0xF9FC;
	rom[0x93A40/2] = 0xF9F0;
	rom[0x93A4C/2] = 0xFD14;
	rom[0x93A58/2] = 0xFD08;
	rom[0x93A66/2] = 0xF9CA;
	rom[0x93A72/2] = 0xF9BE;

}

void neogeo_bootleg_sx_decrypt( int value )
{
	int sx_size = memory_region_length( REGION_GFX1 );
	UINT8 *rom = memory_region( REGION_GFX1 );
	int i;

	if (value == 1)
	{
		UINT8 *buf = malloc( sx_size );
		memcpy( buf, rom, sx_size );

		for( i = 0; i < sx_size; i += 0x10 )
		{
			memcpy( &rom[ i ], &buf[ i + 8 ], 8 );
			memcpy( &rom[ i + 8 ], &buf[ i ], 8 );
		}
		free( buf );
	}
	else if (value == 2)
	{
		for( i = 0; i < sx_size; i++ )
			rom[ i ] = BITSWAP8( rom[ i ], 7, 6, 0, 4, 3, 2, 1, 5 );
	}
}

void neogeo_bootleg_cx_decrypt( void )
{
	int i;
	int cx_size = memory_region_length( REGION_GFX3 );
	UINT8 *rom = memory_region( REGION_GFX3 );
	UINT8 *buf = malloc( cx_size );

	memcpy( buf, rom, cx_size );

	for( i = 0; i < cx_size / 0x40; i++ ){
		memcpy( &rom[ i * 0x40 ], &buf[ (i ^ 1) * 0x40 ], 0x40 );
	}

	free( buf );
}

static void cthd2003_neogeo_gfx_address_fix_do(int start, int end, int bit3shift, int bit2shift, int bit1shift, int bit0shift)
{
	int i,j;
	int tilesize=128;

	UINT8* rom = (UINT8*)malloc(16*tilesize);	/* 16 tiles buffer */
	UINT8* realrom = memory_region(REGION_GFX3) + start*tilesize;

	for (i = 0; i < (end-start)/16; i++) {
		for (j = 0; j < 16; j++) {
			int offset = (((j&1)>>0)<<bit0shift)
					+(((j&2)>>1)<<bit1shift)
					+(((j&4)>>2)<<bit2shift)
					+(((j&8)>>3)<<bit3shift);

			memcpy(rom+j*tilesize, realrom+offset*tilesize, tilesize);
		}
		memcpy(realrom,rom,tilesize*16);
		realrom+=16*tilesize;
	}
	free(rom);
}

static void cthd2003_neogeo_gfx_address_fix(int start, int end)
{
	cthd2003_neogeo_gfx_address_fix_do(start+512*0, end+512*0, 0,3,2,1);
	cthd2003_neogeo_gfx_address_fix_do(start+512*1, end+512*1, 1,0,3,2);
	cthd2003_neogeo_gfx_address_fix_do(start+512*2, end+512*2, 2,1,0,3);
	/* skip 3 & 4 */
	cthd2003_neogeo_gfx_address_fix_do(start+512*5, end+512*5, 0,1,2,3);
	cthd2003_neogeo_gfx_address_fix_do(start+512*6, end+512*6, 0,1,2,3);
	cthd2003_neogeo_gfx_address_fix_do(start+512*7, end+512*7, 0,2,3,1);
}

static void cthd2003_c(int pow)
{
	int i;

	for (i=0; i<=192; i+=8)
		cthd2003_neogeo_gfx_address_fix(i*512,i*512+512);

	for (i=200; i<=392; i+=8)
		cthd2003_neogeo_gfx_address_fix(i*512,i*512+512);

	for (i=400; i<=592; i+=8)
		cthd2003_neogeo_gfx_address_fix(i*512,i*512+512);

	for (i=600; i<=792; i+=8)
		cthd2003_neogeo_gfx_address_fix(i*512,i*512+512);

	for (i=800; i<=992; i+=8)
		cthd2003_neogeo_gfx_address_fix(i*512,i*512+512);

	for (i=1000; i<=1016; i+=8)
		cthd2003_neogeo_gfx_address_fix(i*512,i*512+512);
}

void decrypt_cthd2003(void)
{
	UINT8 *romdata = memory_region(REGION_GFX1);
	UINT8*tmp = (UINT8*)malloc(8*128*128);

	memcpy(tmp+8*0*128, romdata+8*0*128, 8*32*128);
	memcpy(tmp+8*32*128, romdata+8*64*128, 8*32*128);
	memcpy(tmp+8*64*128, romdata+8*32*128, 8*32*128);
	memcpy(tmp+8*96*128, romdata+8*96*128, 8*32*128);
	memcpy(romdata, tmp, 8*128*128);

	romdata = memory_region(REGION_CPU2)+0x10000;
 	memcpy(tmp+8*0*128, romdata+8*0*128, 8*32*128);
	memcpy(tmp+8*32*128, romdata+8*64*128, 8*32*128);
 	memcpy(tmp+8*64*128, romdata+8*32*128, 8*32*128);
	memcpy(tmp+8*96*128, romdata+8*96*128, 8*32*128);
	memcpy(romdata, tmp, 8*128*128);

 	free(tmp);

	memcpy(romdata-0x10000,romdata,0x10000);;

	cthd2003_c(0);
}

static WRITE16_HANDLER ( cthd2003_bankswitch_w )
{
	int bankaddress;
	static int cthd2003_banks[8] =
	{
		1,0,1,0,1,0,3,2,
	};
	if (offset == 0)
	{
		bankaddress = 0x100000 + cthd2003_banks[data&7]*0x100000;
		neogeo_set_cpu1_second_bank(bankaddress);
	}
}

void patch_cthd2003( void )
{
	/* patches thanks to razoola */
	int i;
	UINT16 *mem16 = (UINT16 *)memory_region(REGION_CPU1);

	/* special ROM banking handler */
    install_mem_write16_handler(0, 0x2ffff0, 0x2fffff, cthd2003_bankswitch_w);
	/* theres still a problem on the character select screen but it seems to be related to cpu core timing issues, */
	/* overclocking the 68k prevents it. */

	/* fix garbage on s1 layer over everything */
	mem16[0xf415a/2] = 0x4ef9;
	mem16[0xf415c/2] = 0x000f;
	mem16[0xf415e/2] = 0x4cf2;
	/* Fix corruption in attract mode before title screen */
	for (i=0x1ae290/2;i < 0x1ae8d0/2; i=i+1)
	{
		mem16[i] = 0x0000;
	}

	/* Fix for title page */
	for (i=0x1f8ef0/2;i < 0x1fa1f0/2; i=i+2)
	{
		mem16[i] -= 0x7000;
		mem16[i+1] -= 0x0010;
 	}

	/* Fix for green dots on title page */
	for (i=0xac500/2;i < 0xac520/2; i=i+1)
	{
		mem16[i] = 0xFFFF;
	}
 	/* Fix for blanks as screen change level end clear */
	mem16[0x991d0/2] = 0xdd03;
	mem16[0x99306/2] = 0xdd03;
	mem16[0x99354/2] = 0xdd03;
 	mem16[0x9943e/2] = 0xdd03;
}

static void ct2k3sp_sx_decrypt( void )
{
	int rom_size = memory_region_length( REGION_GFX1 );
	UINT8 *rom = memory_region( REGION_GFX1 );
	UINT8 *buf = malloc( rom_size );
	int i;
	int ofst;

	memcpy( buf, rom, rom_size );

	for( i = 0; i < rom_size; i++ ){
		ofst = BITSWAP24( (i & 0x1ffff), 23, 22, 21, 20, 19, 18, 17,  3,
									      0,  1,  4,  2, 13, 14, 16, 15,
										  5,  6, 11, 10,  9,  8,  7, 12 );

		ofst += (i >> 17) << 17;

		rom[ i ] = buf[ ofst ];
	}

	memcpy( buf, rom, rom_size );

	memcpy( &rom[ 0x08000 ], &buf[ 0x10000 ], 0x8000 );
	memcpy( &rom[ 0x10000 ], &buf[ 0x08000 ], 0x8000 );
	memcpy( &rom[ 0x28000 ], &buf[ 0x30000 ], 0x8000 );
	memcpy( &rom[ 0x30000 ], &buf[ 0x28000 ], 0x8000 );

	free( buf );
}


void decrypt_ct2k3sp(void)
{
	UINT8 *romdata = memory_region(REGION_CPU2)+0x10000;
	UINT8*tmp = (UINT8*)malloc(8*128*128);
	memcpy(tmp+8*0*128, romdata+8*0*128, 8*32*128);
	memcpy(tmp+8*32*128, romdata+8*64*128, 8*32*128);
	memcpy(tmp+8*64*128, romdata+8*32*128, 8*32*128);
	memcpy(tmp+8*96*128, romdata+8*96*128, 8*32*128);
	memcpy(romdata, tmp, 8*128*128);

	free(tmp);
	memcpy(romdata-0x10000,romdata,0x10000);
	ct2k3sp_sx_decrypt();
	cthd2003_c(0);
}

void kof2002_decrypt_68k(void)
{
	int i;
	static const unsigned int sec[]={0x100000,0x280000,0x300000,0x180000,0x000000,0x380000,0x200000,0x080000};
	UINT8 *src = memory_region(REGION_CPU1)+0x100000;
	UINT8 *dst = malloc(0x400000);
	if (dst)
	{
		memcpy( dst, src, 0x400000 );
		for( i=0; i<8; ++i )
		{
			memcpy( src+i*0x80000, dst+sec[i], 0x80000 );
		}
	free(dst);
	}
}

void kf2k2mp_decrypt( void )
{
	int i,j;

	unsigned char *src = memory_region(REGION_CPU1);
	unsigned char *dst = (unsigned char*)malloc(0x80);

	memcpy(src, src + 0x300000, 0x500000);

	if (dst)
	{
		for (i = 0; i < 0x800000; i+=0x80)
		{
			for (j = 0; j < 0x80 / 2; j++)
			{
				int ofst = BITSWAP8( j, 6, 7, 2, 3, 4, 5, 0, 1 );
				memcpy(dst + j * 2, src + i + ofst * 2, 2);
			}
			memcpy(src + i, dst, 0x80);
		}
	}
	free(dst);
}

void kof2km2_px_decrypt( void )
{
	unsigned char *src = memory_region(REGION_CPU1);
	unsigned char *dst = (unsigned char*)malloc(0x600000);

	memcpy (dst + 0x000000, src + 0x1C0000, 0x040000);
	memcpy (dst + 0x040000, src + 0x140000, 0x080000);
	memcpy (dst + 0x0C0000, src + 0x100000, 0x040000);
	memcpy (dst + 0x100000, src + 0x200000, 0x400000);
	memcpy (src + 0x000000, dst + 0x000000, 0x600000);
	free (dst);
}

void decrypt_kof2k4se_68k( void )
{
	UINT8 *src = memory_region(REGION_CPU1)+0x100000;
	UINT8 *dst = malloc(0x400000);
	int i;
	unsigned int sec[] = {0x300000,0x200000,0x100000,0x000000};
	if (dst)
	{
		memcpy(dst,src,0x400000);

		for(i = 0; i < 4; ++i)
		{
		memcpy(src+i*0x100000,dst+sec[i],0x100000);
		}
			free(dst);
	}
}

static UINT16 kof10thExtraRAMB[0x01000];

static void kof10thBankswitch(unsigned int nBank)
{
	nBank = 0x100000 + ((nBank & 7) << 20);
	if (nBank >= 0x700000)
		nBank = 0x100000;
	neogeo_set_cpu1_second_bank(nBank);
}

READ16_HANDLER( kof10th_RAMB_r )
{
	return kof10thExtraRAMB[offset];
}

WRITE16_HANDLER( kof10th_custom_w )
{
	if (!kof10thExtraRAMB[0xFFE]) { /* Write to RAM bank A */
		UINT16 *prom = (UINT16*)memory_region( REGION_CPU1 );
		COMBINE_DATA(&prom[(0xE0000/2) + (offset & 0xFFFF)]);
	} else {
/*      S data should be written here... ??  scrambled?? */
/*      UINT16 *prom = (UINT16*)memory_region( REGION_GFX1 ); */
/*      UINT8 datalow = BITSWAP8((data&0xff)^0xf3,7,6,0,4,3,2,1,5); */
/*      UINT8 datahigh = BITSWAP8(((data>>8)&0xff)^0xf3,7,6,0,4,3,2,1,5); */
/*      data = datalow | datahigh<<8; */
/*      COMBINE_DATA(&prom[offset & 0xFFFF]); */
/*      decodechar(Machine->gfx[0], (offset&0xffff)/16, (UINT8 *)prom, &kof10th_layout); */

	}
}

static WRITE16_HANDLER( kof10th_bankswitch_w )
{
	if (offset >= 0x5F000) {
		if (offset == 0x5FFF8) { /* Standard bankswitch */
			kof10thBankswitch(data);
		} else if (offset == 0x5FFFC && kof10thExtraRAMB[0xFFC] != data) {
			UINT8 *src = memory_region( REGION_CPU1 );
			memcpy (src + 0x400,  src + ((data & 1) ? 0x800400 : 0x700400), 0xdfbff);
		}
		COMBINE_DATA(&kof10thExtraRAMB[offset & 0xFFF]);
	} else {
		/* Usually writes 0x8EF3 or 0x7DF3, sometimes writes 0x0003 to offset 0x25FFF0 */
	}
}

void install_kof10th_protection ( void )
{
	install_mem_read16_handler(0, 0x2fe000, 0x2fffff, kof10th_RAMB_r);
	install_mem_write16_handler(0, 0x200000, 0x23ffff, kof10th_custom_w);
	install_mem_write16_handler(0, 0x240000, 0x2fffff, kof10th_bankswitch_w);
}

void decrypt_kof10th( void )
{
	int i, j;
	UINT8 *dst = malloc(0x900000);
	UINT8 *src = memory_region( REGION_CPU1 );
	UINT8 *srm = memory_region( REGION_GFX1 );

	if (dst) {
		memcpy(dst + 0x000000, src + 0x600000, 0x100000); /* Correct? */
		memcpy(dst + 0x100000, src + 0x000000, 0x800000);
		for (i = 0; i < 0x900000; i++) {
			j = (i&0xFFF000) + BITSWAP16(i&0xFFF,15,14,13,12,11,2,9,8,7,1,5,4,3,10,6,0);
			src[j] = dst[i];
		}
		free(dst);
	}

	/* Altera protection chip patches these over P ROM */
	((UINT16*)src)[0x0124/2] = 0x000d; /* Enables XOR for RAM moves, forces SoftDIPs, and USA region */
	((UINT16*)src)[0x0126/2] = 0xf7a8;

	((UINT16*)src)[0x8bf4/2] = 0x4ef9; /* Run code to change "S" data */
	((UINT16*)src)[0x8bf6/2] = 0x000d;
	((UINT16*)src)[0x8bf8/2] = 0xf980;

 	for (i = 0; i < 0x10000; i++) { /* Get S data, should be done on the fly */
		srm[0x00000+(i^1)]=BITSWAP8(src[0x600000+i]^0xf3,7,6,0,4,3,2,1,5);
 		srm[0x10000+(i^1)]=BITSWAP8(src[0x6d0000+i]^0xf3,7,6,0,4,3,2,1,5);
	}
 	for (i = 0; i < 0x04000; i++) {
		srm[0x02000+(i^1)]=BITSWAP8(src[0x6c2000+i]^0xf3,7,6,0,4,3,2,1,5);
		srm[0x12000+(i^1)]=BITSWAP8(src[0x612000+i]^0xf3,7,6,0,4,3,2,1,5);
	}
}

void decrypt_kf10thep(void)
{
	int i;
	UINT16 *rom = (UINT16*)memory_region(REGION_CPU1);
	UINT8  *src = memory_region(REGION_CPU1);
	UINT16 *buf = (UINT16*)memory_region(REGION_USER4);
	UINT8 *srom = (UINT8*)memory_region(REGION_GFX1);
	UINT8 *sbuf = malloc(0x20000);

	UINT8 *dst = (UINT8*)malloc(0x200000);

	memcpy(dst,buf,0x200000);
	memcpy(src+0x000000,dst+0x060000,0x20000);
	memcpy(src+0x020000,dst+0x100000,0x20000);
	memcpy(src+0x040000,dst+0x0e0000,0x20000);
	memcpy(src+0x060000,dst+0x180000,0x20000);
	memcpy(src+0x080000,dst+0x020000,0x20000);
	memcpy(src+0x0a0000,dst+0x140000,0x20000);
	memcpy(src+0x0c0000,dst+0x0c0000,0x20000);
	memcpy(src+0x0e0000,dst+0x1a0000,0x20000);
	memcpy(src+0x0002e0,dst+0x0402e0,0x6a); /* copy banked code to a new memory region */
	memcpy(src+0x0f92bc,dst+0x0492bc,0xb9e); /* copy banked code to a new memory region */
	for (i=0xf92bc/2;i < 0xf9e58/2 ;i++)
	{
		if (rom[i+0] == 0x4eb9 && rom[i+1] == 0x0000) rom[i+1] = 0x000F; /* correct JSR in moved code */
		if (rom[i+0] == 0x4ef9 && rom[i+1] == 0x0000) rom[i+1] = 0x000F; /* correct JMP in moved code */
	}
	rom[0x00342/2] = 0x000f;
	free(dst);

	for (i=0;i<0x20000;i++)
		sbuf[i]=srom[i^0x8];

	memcpy(srom,sbuf,0x20000);
	free(sbuf);
}

static void kf2k5uni_px_decrypt( void )
{
	int i, j, ofst;
	unsigned char *src = memory_region( REGION_CPU1 );
	unsigned char *dst = (unsigned char*)malloc(0x80);

	for (i = 0; i < 0x800000; i+=0x80)
	{
		for (j = 0; j < 0x80; j+=2)
		{
			ofst = BITSWAP8(j, 0, 3, 4, 5, 6, 1, 2, 7);
			memcpy(dst + j, src + i + ofst, 2);
		}
		memcpy(src + i, dst, 0x80);
	}
	free(dst);

	memcpy(src, src + 0x600000, 0x100000); /* Seems to be the same as kof10th */
}

static void kf2k5uni_sx_decrypt( void )
{
	int i;
	UINT8 *srom = memory_region( REGION_GFX1 );

	for (i = 0; i < 0x20000; i++)
		srom[i] = BITSWAP8(srom[i], 4, 5, 6, 7, 0, 1, 2, 3);
}

static void kf2k5uni_mx_decrypt( void )
{
	int i;
	UINT8 *mrom = memory_region( REGION_CPU2 );

	for (i = 0; i < 0x30000; i++)
		mrom[i] = BITSWAP8(mrom[i], 4, 5, 6, 7, 0, 1, 2, 3);
}

void decrypt_kf2k5uni(void)
{
	kf2k5uni_px_decrypt();
	kf2k5uni_sx_decrypt();
	kf2k5uni_mx_decrypt();
}

void kof2003_decrypt_68k( void )
{
	static const unsigned char xor1[0x20] = { 0x3B, 0x6A, 0xF7, 0xB7, 0xE8, 0xA9, 0x20, 0x99, 0x9F, 0x39, 0x34, 0x0C, 0xC3, 0x9A, 0xA5, 0xC8, 0xB8, 0x18, 0xCE, 0x56, 0x94, 0x44, 0xE3, 0x7A, 0xF7, 0xDD, 0x42, 0xF0, 0x18, 0x60, 0x92, 0x9F };
	static const unsigned char xor2[0x20] = { 0x2F, 0x02, 0x60, 0xBB, 0x77, 0x01, 0x30, 0x08, 0xD8, 0x01, 0xA0, 0xDF, 0x37, 0x0A, 0xF0, 0x65, 0x28, 0x03, 0xD0, 0x23, 0xD3, 0x03, 0x70, 0x42, 0xBB, 0x06, 0xF0, 0x28, 0xBA, 0x0F, 0xF0, 0x7A };
	int i;
	int ofst;
	int rom_size = 0x900000;
	UINT8 *rom = memory_region( REGION_CPU1 );
	UINT8 *buf = malloc( rom_size );

	for (i = 0; i < 0x100000; i++)
	{
		rom[ 0x800000 + i ] ^= rom[ 0x100002 | i ];
	}
	for( i = 0; i < 0x100000; i++)
	{
		rom[ i ] ^= xor1[ (i % 0x20) ];
	}
	for( i = 0x100000; i < 0x800000; i++)
	{
		rom[ i ] ^= xor2[ (i % 0x20) ];
	}
	for( i = 0x100000; i < 0x800000; i += 4)
	{
		UINT16 *rom16 = (UINT16*)&rom[i + 1];
		*rom16 = BITSWAP16( *rom16, 15, 14, 13, 12, 5, 4, 7, 6, 9, 8, 11, 10, 3, 2, 1, 0 );
	}
	for( i = 0; i < 0x0100000 / 0x10000; i++ )
	{
		ofst = (i & 0xf0) + BITSWAP8((i & 0x0f), 7, 6, 5, 4, 0, 1, 2, 3);
		memcpy( &buf[ i * 0x10000 ], &rom[ ofst * 0x10000 ], 0x10000 );
	}
	for( i = 0x100000; i < 0x900000; i += 0x100)
	{
		ofst = (i & 0xf000ff) + ((i & 0x000f00) ^ 0x00800) + (BITSWAP8( ((i & 0x0ff000) >> 12), 4, 5, 6, 7, 1, 0, 3, 2 ) << 12);
		memcpy( &buf[ i ], &rom[ ofst ], 0x100 );
	}
	memcpy (&rom[0x000000], &buf[0x000000], 0x100000);
	memcpy (&rom[0x100000], &buf[0x800000], 0x100000);
	memcpy (&rom[0x200000], &buf[0x100000], 0x700000);
	free( buf );
}

static unsigned short CartRAM[0x1000];

void pvc_w8(unsigned int offset, unsigned char data)
{
	*(((unsigned char*)CartRAM)+BYTE_XOR_LE(offset))=data;
}

unsigned char pvc_r8(unsigned int offset)
{
	return *(((unsigned char*)CartRAM)+BYTE_XOR_LE(offset));
}

void pvc_prot1( void )
{
	unsigned char b1, b2;
	b1 = pvc_r8(0x1fe1);
	b2 = pvc_r8(0x1fe0);
	pvc_w8(0x1fe2,(((b2>>0)&0xf)<<1)|((b1>>4)&1));
	pvc_w8(0x1fe3,(((b2>>4)&0xf)<<1)|((b1>>5)&1));
	pvc_w8(0x1fe4,(((b1>>0)&0xf)<<1)|((b1>>6)&1));
	pvc_w8(0x1fe5, (b1>>7));
}


void pvc_prot2( void ) /* on writes to e8/e9/ea/eb */
{
	unsigned char b1, b2, b3, b4;
	b1 = pvc_r8(0x1fe9);
	b2 = pvc_r8(0x1fe8);
	b3 = pvc_r8(0x1feb);
	b4 = pvc_r8(0x1fea);
	pvc_w8(0x1fec,(b2>>1)|((b1>>1)<<4));
	pvc_w8(0x1fed,(b4>>1)|((b2&1)<<4)|((b1&1)<<5)|((b4&1)<<6)|((b3&1)<<7));
}

void pvc_write_bankswitch( void )
{
	UINT32 bankaddress;
	bankaddress = ((CartRAM[0xff8]>>8)|(CartRAM[0xff9]<<8));
	*(((unsigned char *)CartRAM) + BYTE_XOR_LE(0x1ff0)) = 0xA0;
	*(((unsigned char *)CartRAM) + BYTE_XOR_LE(0x1ff1)) &= 0xFE;
	*(((unsigned char *)CartRAM) + BYTE_XOR_LE(0x1ff3)) &= 0x7F;
	neogeo_set_cpu1_second_bank(bankaddress+0x100000);
}

static READ16_HANDLER( pvc_prot_r )
{
	return CartRAM[ offset ];
}

static WRITE16_HANDLER( pvc_prot_w )
{
	COMBINE_DATA( &CartRAM[ offset ] );
	if (offset == 0xFF0)pvc_prot1();
	else if(offset >= 0xFF4 && offset <= 0xFF5)pvc_prot2();
	else if(offset >= 0xFF8)pvc_write_bankswitch();
}

void install_pvc_protection( void )
{
	install_mem_read16_handler(0, 0x2fe000, 0x2fffff, pvc_prot_r);
	install_mem_write16_handler(0, 0x2fe000, 0x2fffff, pvc_prot_w);
}

static UINT16 kof2003_tbl[4096];

READ16_HANDLER( kof2003_r)
{
	return kof2003_tbl[offset];
}

WRITE16_HANDLER( kof2003_w )
{
	data = COMBINE_DATA(&kof2003_tbl[offset]);
	if (offset == 0x1ff0/2 || offset == 0x1ff2/2) {
		UINT8* cr = (UINT8 *)kof2003_tbl;
		UINT32 address = (cr[0x1ff3]<<16)|(cr[0x1ff2]<<8)|cr[0x1ff1];
		UINT8 prt = cr[0x1ff2];
		UINT8* mem = (UINT8 *)memory_region(REGION_CPU1);

		cr[0x1ff0] =  0xa0;
		cr[0x1ff1] &= 0xfe;
		cr[0x1ff3] &= 0x7f;
		neogeo_set_cpu1_second_bank(address+0x100000);

		mem[0x58196] = prt;
	}
}

WRITE16_HANDLER( kof2003p_w )
{
	data = COMBINE_DATA(&kof2003_tbl[offset]);
	if (offset == 0x1ff0/2 || offset == 0x1ff2/2) {
		UINT8* cr = (UINT8 *)kof2003_tbl;
		UINT32 address = (cr[0x1ff3]<<16)|(cr[0x1ff2]<<8)|cr[0x1ff0];
		UINT8 prt = cr[0x1ff2];
		UINT8* mem = (UINT8 *)memory_region(REGION_CPU1);

		cr[0x1ff0] &= 0xfe;
		cr[0x1ff3] &= 0x7f;
		neogeo_set_cpu1_second_bank(address+0x100000);

		mem[0x58196] = prt;
	}
}

void kf2k3bl_install_protection(void)
{
    install_mem_read16_handler( 0, 0x2fe000, 0x2fffff, kof2003_r );
    install_mem_write16_handler( 0, 0x2fe000, 0x2fffff, kof2003_w );
}

void kf2k3pl_px_decrypt( void )
{
	UINT16*tmp = malloc(0x100000);
	UINT16*rom = (UINT16*)memory_region( REGION_CPU1 );
	int j;
	int i;

	for (i = 0;i < 0x700000/2;i+=0x100000/2)
	{
		memcpy(tmp,&rom[i],0x100000);
		for (j = 0;j < 0x100000/2;j++)
			rom[i+j] = tmp[BITSWAP24(j,23,22,21,20,19,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18)];
	}
	free(tmp);

	/* patched by Altera protection chip on PCB */
	rom[0xf38ac/2] = 0x4e75;
}

void kf2k3pl_install_protection(void)
{
    install_mem_read16_handler( 0, 0x2fe000, 0x2fffff, kof2003_r );
    install_mem_write16_handler( 0, 0x2fe000, 0x2fffff,  kof2003p_w );
}

void kf2k3upl_px_decrypt( void )
{
	{
		UINT8 *src = memory_region(REGION_CPU1);
		memmove(src+0x100000, src, 0x600000);
		memmove(src, src+0x700000, 0x100000);
	}

	{

		int ofst;
		int i;
		UINT8 *rom = memory_region( REGION_CPU1 ) + 0xfe000;
		UINT8 *buf = memory_region( REGION_CPU1 ) + 0xd0610;

		for( i = 0; i < 0x2000 / 2; i++ ){
			ofst = (i & 0xff00) + BITSWAP8( (i & 0x00ff), 7, 6, 0, 4, 3, 2, 1, 5 );
			memcpy( &rom[ i * 2 ], &buf[ ofst * 2 ], 2 );
		}
	}
}

void kf2k3upl_install_protection(void)
{
    install_mem_read16_handler( 0, 0x2fe000, 0x2fffff, kof2003_r );
    install_mem_write16_handler( 0, 0x2fe000, 0x2fffff, kof2003_w );
}

/* kof99, garou, garouo, mslug3 and kof2000 have and SMA chip which contains program code and decrypts the 68k roms */
void kof99_decrypt_68k(void)
{
	UINT16 *rom;
	int i,j;

	rom = (UINT16 *)(memory_region(REGION_CPU1) + 0x100000);
	/* swap data lines on the whole ROMs */
	for (i = 0;i < 0x800000/2;i++)
	{
		rom[i] = BITSWAP16(rom[i],13,7,3,0,9,4,5,6,1,12,8,14,10,11,2,15);
	}

	/* swap address lines for the banked part */
	for (i = 0;i < 0x600000/2;i+=0x800/2)
	{
		UINT16 buffer[0x800/2];
		memcpy(buffer,&rom[i],0x800);
		for (j = 0;j < 0x800/2;j++)
		{
			rom[i+j] = buffer[BITSWAP24(j,23,22,21,20,19,18,17,16,15,14,13,12,11,10,6,2,4,9,8,3,1,7,0,5)];
		}
	}

	/* swap address lines & relocate fixed part */
	rom = (UINT16 *)memory_region(REGION_CPU1);
	for (i = 0;i < 0x0c0000/2;i++)
	{
		rom[i] = rom[0x700000/2 + BITSWAP24(i,23,22,21,20,19,18,11,6,14,17,16,5,8,10,12,0,4,3,2,7,9,15,13,1)];
	}
}

static WRITE16_HANDLER( kof99_bankswitch_w )
{
	int bankaddress;
	static int bankoffset[64] =
	{
		0x000000, 0x100000, 0x200000, 0x300000,
		0x3cc000, 0x4cc000, 0x3f2000, 0x4f2000,
		0x407800, 0x507800, 0x40d000, 0x50d000,
		0x417800, 0x517800, 0x420800, 0x520800,
		0x424800, 0x524800, 0x429000, 0x529000,
		0x42e800, 0x52e800, 0x431800, 0x531800,
		0x54d000, 0x551000, 0x567000, 0x592800,
		0x588800, 0x581800, 0x599800, 0x594800,
		0x598000,	/* rest not used? */
	};

	/* unscramble bank number */
	data =
		(((data>>14)&1)<<0)+
		(((data>> 6)&1)<<1)+
		(((data>> 8)&1)<<2)+
		(((data>>10)&1)<<3)+
		(((data>>12)&1)<<4)+
		(((data>> 5)&1)<<5);

	bankaddress = 0x100000 + bankoffset[data];

	neogeo_set_cpu1_second_bank(bankaddress);
}

void kof99_install_protection(void)
{
	install_mem_write16_handler(0, 0x2ffff0, 0x2ffff1, kof99_bankswitch_w);
	install_mem_read16_handler(0, 0x2fe446, 0x2fe447, prot_9a37_r);
	install_mem_read16_handler(0, 0x2ffff8, 0x2ffff9, sma_random_r);
	install_mem_read16_handler(0, 0x2ffffa, 0x2ffffb, sma_random_r);
}

void garou_decrypt_68k(void)
{
	data16_t *rom;
	int i,j;

	/* thanks to Razoola and Mr K for the info */
	rom = (data16_t *)(memory_region(REGION_CPU1) + 0x100000);
	/* swap data lines on the whole ROMs */
	for (i = 0;i < 0x800000/2;i++)
	{
		rom[i] = BITSWAP16(rom[i],13,12,14,10,8,2,3,1,5,9,11,4,15,0,6,7);
	}

	/* swap address lines & relocate fixed part */
	rom = (data16_t *)memory_region(REGION_CPU1);
	for (i = 0;i < 0x0c0000/2;i++)
	{
		rom[i] = rom[0x710000/2 + BITSWAP24(i,23,22,21,20,19,18,4,5,16,14,7,9,6,13,17,15,3,1,2,12,11,8,10,0)];
	}

	/* swap address lines for the banked part */
	rom = (data16_t *)(memory_region(REGION_CPU1) + 0x100000);
	for (i = 0;i < 0x800000/2;i+=0x8000/2)
	{
		data16_t buffer[0x8000/2];
		memcpy(buffer,&rom[i],0x8000);
		for (j = 0;j < 0x8000/2;j++)
		{
			rom[i+j] = buffer[BITSWAP24(j,23,22,21,20,19,18,17,16,15,14,9,4,8,3,13,6,2,7,0,12,1,11,10,5)];
		}
	}
}

static WRITE16_HANDLER( garou_bankswitch_w )
{
	/* thanks to Razoola and Mr K for the info */
	int bankaddress;
	static int bankoffset[64] =
	{
		0x000000, 0x100000, 0x200000, 0x300000, /* 00 */
		0x280000, 0x380000, 0x2d0000, 0x3d0000, /* 04 */
		0x2f0000, 0x3f0000, 0x400000, 0x500000, /* 08 */
		0x420000, 0x520000, 0x440000, 0x540000, /* 12 */
		0x498000, 0x598000, 0x4a0000, 0x5a0000, /* 16 */
		0x4a8000, 0x5a8000, 0x4b0000, 0x5b0000, /* 20 */
		0x4b8000, 0x5b8000, 0x4c0000, 0x5c0000, /* 24 */
		0x4c8000, 0x5c8000, 0x4d0000, 0x5d0000, /* 28 */
		0x458000, 0x558000, 0x460000, 0x560000, /* 32 */
		0x468000, 0x568000, 0x470000, 0x570000, /* 36 */
		0x478000, 0x578000, 0x480000, 0x580000, /* 40 */
		0x488000, 0x588000, 0x490000, 0x590000, /* 44 */
		0x5d0000, 0x5d8000, 0x5e0000, 0x5e8000, /* 48 */
		0x5f0000, 0x5f8000, 0x600000, /* rest not used? */
	};

	/* unscramble bank number */
	data =
		(((data>> 5)&1)<<0)+
		(((data>> 9)&1)<<1)+
		(((data>> 7)&1)<<2)+
		(((data>> 6)&1)<<3)+
		(((data>>14)&1)<<4)+
		(((data>>12)&1)<<5);

	bankaddress = 0x100000 + bankoffset[data];

	neogeo_set_cpu1_second_bank(bankaddress);
}

void garou_install_protection(void)
{
	install_mem_write16_handler(0, 0x2fffc0, 0x2fffc1, garou_bankswitch_w);
	install_mem_read16_handler(0, 0x2fe446, 0x2fe447, prot_9a37_r);
	install_mem_read16_handler(0, 0x2ffff8, 0x2ffff9, sma_random_r);
	install_mem_read16_handler(0, 0x2ffffa, 0x2ffffb, sma_random_r);
}

void garouo_decrypt_68k(void)
{
	data16_t *rom;
	int i,j;

	/* thanks to Razoola and Mr K for the info */
	rom = (data16_t *)(memory_region(REGION_CPU1) + 0x100000);
	/* swap data lines on the whole ROMs */
	for (i = 0;i < 0x800000/2;i++)
	{
		rom[i] = BITSWAP16(rom[i],14,5,1,11,7,4,10,15,3,12,8,13,0,2,9,6);
	}

	/* swap address lines & relocate fixed part */
	rom = (data16_t *)memory_region(REGION_CPU1);
	for (i = 0;i < 0x0c0000/2;i++)
	{
		rom[i] = rom[0x7f8000/2 + BITSWAP24(i,23,22,21,20,19,18,5,16,11,2,6,7,17,3,12,8,14,4,0,9,1,10,15,13)];
	}

	/* swap address lines for the banked part */
	rom = (data16_t *)(memory_region(REGION_CPU1) + 0x100000);
	for (i = 0;i < 0x800000/2;i+=0x8000/2)
	{
		data16_t buffer[0x8000/2];
		memcpy(buffer,&rom[i],0x8000);
		for (j = 0;j < 0x8000/2;j++)
		{
			rom[i+j] = buffer[BITSWAP24(j,23,22,21,20,19,18,17,16,15,14,12,8,1,7,11,3,13,10,6,9,5,4,0,2)];
		}
	}
}

static WRITE16_HANDLER( garouo_bankswitch_w )
{
	/* thanks to Razoola and Mr K for the info */
	int bankaddress;
	static int bankoffset[64] =
	{
		0x000000, 0x100000, 0x200000, 0x300000, /* 00 */
		0x280000, 0x380000, 0x2d0000, 0x3d0000, /* 04 */
		0x2c8000, 0x3c8000, 0x400000, 0x500000, /* 08 */
		0x420000, 0x520000, 0x440000, 0x540000, /* 12 */
		0x598000, 0x698000, 0x5a0000, 0x6a0000, /* 16 */
		0x5a8000, 0x6a8000, 0x5b0000, 0x6b0000, /* 20 */
		0x5b8000, 0x6b8000, 0x5c0000, 0x6c0000, /* 24 */
		0x5c8000, 0x6c8000, 0x5d0000, 0x6d0000, /* 28 */
		0x458000, 0x558000, 0x460000, 0x560000, /* 32 */
		0x468000, 0x568000, 0x470000, 0x570000, /* 36 */
		0x478000, 0x578000, 0x480000, 0x580000, /* 40 */
		0x488000, 0x588000, 0x490000, 0x590000, /* 44 */
		0x5d8000, 0x6d8000, 0x5e0000, 0x6e0000, /* 48 */
		0x5e8000, 0x6e8000, 0x6e8000, 0x000000, /* 52 */
		0x000000, 0x000000, 0x000000, 0x000000, /* 56 */
		0x000000, 0x000000, 0x000000, 0x000000, /* 60 */
	};

	/* unscramble bank number */
	data =
		(((data>> 4)&1)<<0)+
		(((data>> 8)&1)<<1)+
		(((data>>14)&1)<<2)+
		(((data>> 2)&1)<<3)+
		(((data>>11)&1)<<4)+
		(((data>>13)&1)<<5);

	bankaddress = 0x100000 + bankoffset[data];

	neogeo_set_cpu1_second_bank(bankaddress);
}

void garouo_install_protection(void)
{
	install_mem_write16_handler(0, 0x2fffc0, 0x2fffc1, garouo_bankswitch_w);
	install_mem_read16_handler(0, 0x2fe446, 0x2fe447, prot_9a37_r);
	install_mem_read16_handler(0, 0x2ffff8, 0x2ffff9, sma_random_r);
	install_mem_read16_handler(0, 0x2ffffa, 0x2ffffb, sma_random_r);
}

void mslug3_decrypt_68k(void)
{
	data16_t *rom;
	int i,j;

	/* thanks to Razoola and Mr K for the info */
	rom = (data16_t *)(memory_region(REGION_CPU1) + 0x100000);
	/* swap data lines on the whole ROMs */
	for (i = 0;i < 0x800000/2;i++)
	{
		rom[i] = BITSWAP16(rom[i],4,11,14,3,1,13,0,7,2,8,12,15,10,9,5,6);
	}

	/* swap address lines & relocate fixed part */
	rom = (data16_t *)memory_region(REGION_CPU1);
	for (i = 0;i < 0x0c0000/2;i++)
	{
		rom[i] = rom[0x5d0000/2 + BITSWAP24(i,23,22,21,20,19,18,15,2,1,13,3,0,9,6,16,4,11,5,7,12,17,14,10,8)];
	}

	/* swap address lines for the banked part */
	rom = (data16_t *)(memory_region(REGION_CPU1) + 0x100000);
	for (i = 0;i < 0x800000/2;i+=0x10000/2)
	{
		data16_t buffer[0x10000/2];
		memcpy(buffer,&rom[i],0x10000);
		for (j = 0;j < 0x10000/2;j++)
		{
			rom[i+j] = buffer[BITSWAP24(j,23,22,21,20,19,18,17,16,15,2,11,0,14,6,4,13,8,9,3,10,7,5,12,1)];
		}
	}
}

static WRITE16_HANDLER( mslug3_bankswitch_w )
{
	/* thanks to Razoola and Mr K for the info */
	int bankaddress;
	static int bankoffset[64] =
	{
	  0x000000, 0x020000, 0x040000, 0x060000, /* 00 */
	  0x070000, 0x090000, 0x0b0000, 0x0d0000, /* 04 */
	  0x0e0000, 0x0f0000, 0x120000, 0x130000, /* 08 */
	  0x140000, 0x150000, 0x180000, 0x190000, /* 12 */
	  0x1a0000, 0x1b0000, 0x1e0000, 0x1f0000, /* 16 */
	  0x200000, 0x210000, 0x240000, 0x250000, /* 20 */
	  0x260000, 0x270000, 0x2a0000, 0x2b0000, /* 24 */
	  0x2c0000, 0x2d0000, 0x300000, 0x310000, /* 28 */
	  0x320000, 0x330000, 0x360000, 0x370000, /* 32 */
	  0x380000, 0x390000, 0x3c0000, 0x3d0000, /* 36 */
	  0x400000, 0x410000, 0x440000, 0x450000, /* 40 */
	  0x460000, 0x470000, 0x4a0000, 0x4b0000, /* 44 */
	  0x4c0000, /* rest not used? */
	};

	/* unscramble bank number */
	data =
		(((data>>14)&1)<<0)+
		(((data>>12)&1)<<1)+
		(((data>>15)&1)<<2)+
		(((data>> 6)&1)<<3)+
		(((data>> 3)&1)<<4)+
		(((data>> 9)&1)<<5);

	bankaddress = 0x100000 + bankoffset[data];

	neogeo_set_cpu1_second_bank(bankaddress);
}

void mslug3_install_protection(void)
{
	install_mem_write16_handler(0, 0x2fffe4, 0x2fffe5, mslug3_bankswitch_w);
	install_mem_read16_handler(0, 0x2fe446, 0x2fe447, prot_9a37_r);
	install_mem_read16_handler(0, 0x2ffff8, 0x2ffff9, sma_random_r);
	install_mem_read16_handler(0, 0x2ffffa, 0x2ffffb, sma_random_r);
}

void kof2000_decrypt_68k(void)
{
	data16_t *rom;
	int i,j;

	/* thanks to Razoola and Mr K for the info */
	rom = (data16_t *)(memory_region(REGION_CPU1) + 0x100000);
	/* swap data lines on the whole ROMs */
	for (i = 0;i < 0x800000/2;i++)
	{
		rom[i] = BITSWAP16(rom[i],12,8,11,3,15,14,7,0,10,13,6,5,9,2,1,4);
	}

	/* swap address lines for the banked part */
	for (i = 0;i < 0x63a000/2;i+=0x800/2)
	{
		data16_t buffer[0x800/2];
		memcpy(buffer,&rom[i],0x800);
		for (j = 0;j < 0x800/2;j++)
		{
			rom[i+j] = buffer[BITSWAP24(j,23,22,21,20,19,18,17,16,15,14,13,12,11,10,4,1,3,8,6,2,7,0,9,5)];
		}
	}

	/* swap address lines & relocate fixed part */
	rom = (data16_t *)memory_region(REGION_CPU1);
	for (i = 0;i < 0x0c0000/2;i++)
	{
		rom[i] = rom[0x73a000/2 + BITSWAP24(i,23,22,21,20,19,18,8,4,15,13,3,14,16,2,6,17,7,12,10,0,5,11,1,9)];
	}
}

static WRITE16_HANDLER( kof2000_bankswitch_w )
{
	/* thanks to Razoola and Mr K for the info */
	int bankaddress;
	static int bankoffset[64] =
	{
		0x000000, 0x100000, 0x200000, 0x300000, /* 00 */
		0x3f7800, 0x4f7800, 0x3ff800, 0x4ff800, /* 04 */
		0x407800, 0x507800, 0x40f800, 0x50f800, /* 08 */
		0x416800, 0x516800, 0x41d800, 0x51d800, /* 12 */
		0x424000, 0x524000, 0x523800, 0x623800, /* 16 */
		0x526000, 0x626000, 0x528000, 0x628000, /* 20 */
		0x52a000, 0x62a000, 0x52b800, 0x62b800, /* 24 */
		0x52d000, 0x62d000, 0x52e800, 0x62e800, /* 28 */
		0x618000, 0x619000, 0x61a000, 0x61a800, /* 32 */
	};

	/* unscramble bank number */
	data =
		(((data>>15)&1)<<0)+
		(((data>>14)&1)<<1)+
		(((data>> 7)&1)<<2)+
		(((data>> 3)&1)<<3)+
		(((data>>10)&1)<<4)+
		(((data>> 5)&1)<<5);

	bankaddress = 0x100000 + bankoffset[data];

	neogeo_set_cpu1_second_bank(bankaddress);
}

void kof2000_install_protection(void)
{
	install_mem_write16_handler(0, 0x2fffec, 0x2fffed, kof2000_bankswitch_w);
	install_mem_read16_handler(0, 0x2fe446, 0x2fe447, prot_9a37_r);
	install_mem_read16_handler(0, 0x2ffff8, 0x2ffff9, sma_random_r);
	install_mem_read16_handler(0, 0x2ffffa, 0x2ffffb, sma_random_r);
}

/* Kof98 uses an early encryption, quite different from the others */
void kof98_decrypt_68k(void)
{
	UINT8 *src = memory_region(REGION_CPU1);
	UINT8 *dst = malloc(0x200000);
	int i, j, k;
	static const unsigned int sec[]={0x000000,0x100000,0x000004,0x100004,0x10000a,0x00000a,0x10000e,0x00000e};
	static const unsigned int pos[]={0x000,0x004,0x00a,0x00e};

	memcpy( dst, src, 0x200000);
	for( i=0x800; i<0x100000; i+=0x200 )
	{
		for( j=0; j<0x100; j+=0x10 )
		{
			for( k=0; k<16; k+=2)
			{
				memcpy( &src[i+j+k],       &dst[ i+j+sec[k/2]+0x100 ], 2 );
				memcpy( &src[i+j+k+0x100], &dst[ i+j+sec[k/2] ],       2 );
			}
			if( i >= 0x080000 && i < 0x0c0000)
			{
				for( k=0; k<4; k++ )
				{
					memcpy( &src[i+j+pos[k]],       &dst[i+j+pos[k]],       2 );
					memcpy( &src[i+j+pos[k]+0x100], &dst[i+j+pos[k]+0x100], 2 );
				}
			}
			else if( i >= 0x0c0000 )
			{
				for( k=0; k<4; k++ )
				{
					memcpy( &src[i+j+pos[k]],       &dst[i+j+pos[k]+0x100], 2 );
					memcpy( &src[i+j+pos[k]+0x100], &dst[i+j+pos[k]],       2 );
				}
			}
		}
		memcpy( &src[i+0x000000], &dst[i+0x000000], 2 );
		memcpy( &src[i+0x000002], &dst[i+0x100000], 2 );
		memcpy( &src[i+0x000100], &dst[i+0x000100], 2 );
		memcpy( &src[i+0x000102], &dst[i+0x100100], 2 );
	}
	memcpy( &src[0x100000], &src[0x200000], 0x400000 );

	free(dst);
}

WRITE16_HANDLER ( kof98_prot_w )
{
	/* info from razoola */
	UINT16* mem16 = (UINT16*)memory_region(REGION_CPU1);

	switch (data)
	{
		case 0x0090:
		logerror ("%06x kof98 - protection 0x0090 old %04x %04x\n",activecpu_get_pc(), mem16[0x100/2], mem16[0x102/2]);
		mem16[0x100/2] = 0x00c2; mem16[0x102/2] = 0x00fd;
		break;

		case 0x00f0:
		logerror ("%06x kof98 - protection 0x00f0 old %04x %04x\n",activecpu_get_pc(), mem16[0x100/2], mem16[0x102/2]);
		mem16[0x100/2] = 0x4e45; mem16[0x102/2] = 0x4f2d;
		break;

		default: /* 00aa is written, but not needed? */
		logerror ("%06x kof98 - unknown protection write %04x\n",activecpu_get_pc(), data);
		break;
	}
}

void install_kof98_protection(void)
{
	/* when 0x20aaaa contains 0x0090 (word) then 0x100 (normally the neogeo header) should return 0x00c200fd
   worked out using real hw */

		install_mem_write16_handler(0, 0x20aaaa, 0x20aaab, kof98_prot_w);
}

void matrim_decrypt_68k(void)
{
	int i;
	unsigned int sec[]={0x100000,0x280000,0x300000,0x180000,0x000000,0x380000,0x200000,0x080000};
	UINT8 *src = memory_region(REGION_CPU1)+0x100000;
	UINT8 *dst = malloc(0x400000);
	if (dst)
	{
		memcpy( dst, src, 0x400000);
		for( i=0; i<8; ++i )
		{
			memcpy( src+i*0x80000, dst+sec[i], 0x80000 );
		}
	free(dst);
	}
}

void svcboot_px_decrypt( void )
{
	static const unsigned char sec[] = {
		0x06, 0x07, 0x01, 0x02, 0x03, 0x04, 0x05, 0x00
	};
	int i;
	int size = memory_region_length( REGION_CPU1 );
	UINT8 *src = memory_region( REGION_CPU1 );
	UINT8 *dst = malloc( size );
	int ofst;
	for( i = 0; i < size / 0x100000; i++ ){
		memcpy( &dst[ i * 0x100000 ], &src[ sec[ i ] * 0x100000 ], 0x100000 );
	}
	for( i = 0; i < size / 2; i++ ){
		ofst = BITSWAP8( (i & 0x0000ff), 7, 6, 1, 0, 3, 2, 5, 4 );
		ofst += (i & 0xffff00);
		memcpy( &src[ i * 2 ], &dst[ ofst * 2 ], 0x02 );
	}
	free( dst );
}

void svcboot_cx_decrypt( void )
{
	static const unsigned char idx_tbl[ 0x10 ] = {
		0, 1, 0, 1, 2, 3, 2, 3, 3, 4, 3, 4, 4, 5, 4, 5,
	};
	static const unsigned char bitswap4_tbl[ 6 ][ 4 ] = {
		{ 3, 0, 1, 2 },
		{ 2, 3, 0, 1 },
		{ 1, 2, 3, 0 },
		{ 0, 1, 2, 3 },
		{ 3, 2, 1, 0 },
		{ 3, 0, 2, 1 },
	};
	int i;
	int size = memory_region_length( REGION_GFX3 );
	UINT8 *src = memory_region( REGION_GFX3 );
	UINT8 *dst = malloc( size );
	int ofst;
	memcpy( dst, src, size );
	for( i = 0; i < size / 0x80; i++ ){
		int idx = idx_tbl[ (i & 0xf00) >> 8 ];
		int bit0 = bitswap4_tbl[ idx ][ 0 ];
		int bit1 = bitswap4_tbl[ idx ][ 1 ];
		int bit2 = bitswap4_tbl[ idx ][ 2 ];
		int bit3 = bitswap4_tbl[ idx ][ 3 ];
		ofst = BITSWAP8( (i & 0x0000ff), 7, 6, 5, 4, bit3, bit2, bit1, bit0 );
		ofst += (i & 0xfffff00);
		memcpy( &src[ i * 0x80 ], &dst[ ofst * 0x80 ], 0x80 );
	}
	free( dst );
}

void samsho5_decrypt_68k(void)
{
	int i;
	static const unsigned int sec[]={0x000000,0x080000,0x700000,0x680000,0x500000,0x180000,0x200000,0x480000,0x300000,0x780000,0x600000,0x280000,0x100000,0x580000,0x400000,0x380000};
	UINT8 *src = memory_region(REGION_CPU1);
	UINT8 *dst = malloc(0x800000);

		memcpy( dst, src, 0x800000 );
		for( i=0; i<16; ++i )
		{
			memcpy( src+i*0x80000, dst+sec[i], 0x80000 );
		}
	free(dst);
}

void samsh5sp_decrypt_68k(void)
{
		/* Descrambling Px by Vorador from speksnk Coneverted to Mame code by James */
	UINT8 *src = memory_region(REGION_CPU1);
	UINT8 *dst = malloc(0x800000);
	int i;
	unsigned int sec[]={0x0,0x1,0xA,0x9,0xC,0xB,0xE,0x5,0x2,0xD,0x8,0xF,0x4,0x7,0x6,0x3};
	if (dst)
	{
  memcpy(dst,src,0x800000);

  for(i=0;i<0x10;i++)
  {
  	memcpy(src+i*0x80000,dst+sec[i]*0x80000,0x80000);
  }
  free(dst);
	}
}

void mslug5_decrypt_68k(void)
{
	static const unsigned char xor1[ 0x20 ] = { 0xc2, 0x4b, 0x74, 0xfd, 0x0b, 0x34, 0xeb, 0xd7, 0x10, 0x6d, 0xf9, 0xce, 0x5d, 0xd5, 0x61, 0x29, 0xf5, 0xbe, 0x0d, 0x82, 0x72, 0x45, 0x0f, 0x24, 0xb3, 0x34, 0x1b, 0x99, 0xea, 0x09, 0xf3, 0x03 };
	static const unsigned char xor2[ 0x20 ] = { 0x36, 0x09, 0xb0, 0x64, 0x95, 0x0f, 0x90, 0x42, 0x6e, 0x0f, 0x30, 0xf6, 0xe5, 0x08, 0x30, 0x64, 0x08, 0x04, 0x00, 0x2f, 0x72, 0x09, 0xa0, 0x13, 0xc9, 0x0b, 0xa0, 0x3e, 0xc2, 0x00, 0x40, 0x2b };
	int i;
	int ofst;
	int rom_size = 0x800000;
	UINT8 *rom = memory_region( REGION_CPU1 );
	UINT8 *buf = malloc( rom_size );

	for( i = 0; i < 0x100000; i++ )
	{
		rom[ i ] ^= xor1[ (BYTE_XOR_LE(i) % 0x20) ];
	}
	for( i = 0x100000; i < 0x800000; i++ )
	{
		rom[ i ] ^= xor2[ (BYTE_XOR_LE(i) % 0x20) ];
	}

	for( i = 0x100000; i < 0x0800000; i += 4 )
	{
		UINT16 rom16;
		rom16 = rom[BYTE_XOR_LE(i+1)] | rom[BYTE_XOR_LE(i+2)]<<8;
		rom16 = BITSWAP16( rom16, 15, 14, 13, 12, 10, 11, 8, 9, 6, 7, 4, 5, 3, 2, 1, 0 );
		rom[BYTE_XOR_LE(i+1)] = rom16&0xff;
		rom[BYTE_XOR_LE(i+2)] = rom16>>8;
	}
	memcpy( buf, rom, rom_size );
	for( i = 0; i < 0x0100000 / 0x10000; i++ )
	{
		ofst = (i & 0xf0) + BITSWAP8( (i & 0x0f), 7, 6, 5, 4, 1, 0, 3, 2 );
		memcpy( &rom[ i * 0x10000 ], &buf[ ofst * 0x10000 ], 0x10000 );
	}
	for( i = 0x100000; i < 0x800000; i += 0x100 )
	{
		ofst = (i & 0xf000ff) + ((i & 0x000f00) ^ 0x00700) + (BITSWAP8( ((i & 0x0ff000) >> 12), 5, 4, 7, 6, 1, 0, 3, 2 ) << 12);
		memcpy( &rom[ i ], &buf[ ofst ], 0x100 );
	}
	memcpy( buf, rom, rom_size );
	memcpy( &rom[ 0x100000 ], &buf[ 0x700000 ], 0x100000 );
	memcpy( &rom[ 0x200000 ], &buf[ 0x100000 ], 0x600000 );
	free( buf );
}

/* kof2003d Init Start */
void kof2003_px_decrypt( void )
{
	const unsigned char xor2[ 0x20 ] = {
		0xb4, 0x0f, 0x40, 0x6c, 0x38, 0x07, 0xd0, 0x3f, 0x53, 0x08, 0x80, 0xaa, 0xbe, 0x07, 0xc0, 0xfa,
		0xd0, 0x08, 0x10, 0xd2, 0xf1, 0x03, 0x70, 0x7e, 0x87, 0x0B, 0x40, 0xf6, 0x2a, 0x0a, 0xe0, 0xf9
	};

	int i;
	int ofst;
	UINT8 *rom, *buf;

	rom = memory_region( REGION_CPU1 );

	for( i = 0x100000; i < 0x800000; i++ ){
		rom[ i ] ^= xor2[ (i % 0x20) ];
	}

	for( i = 0x100000; i < 0x800000; i += 4 ){
		UINT16 *rom16 = (UINT16*)&rom[ i + 1 ];
		*rom16 = BITSWAP16( *rom16, 15, 14, 13, 12, 4, 5, 6, 7, 8, 9, 10, 11, 3, 2, 1, 0 );
	}

	buf = malloc( 0x800000 );
	memcpy( buf, rom, 0x800000 );

	for( i = 0; i < 0x0100000 / 0x10000; i++ ){
		ofst = (i & 0xf0) + BITSWAP8( (i & 0x0f), 7, 6, 5, 4, 1, 0, 3, 2 );
		memcpy( &rom[ i * 0x10000 ], &buf[ ofst * 0x10000 ], 0x10000 );
	}

	for( i = 0x100000; i < 0x800000; i += 0x100 ){
		ofst = (i & 0xf000ff) + 
			   ((i & 0x000f00) ^ 0x00300) +
			   (BITSWAP8( ((i & 0x0ff000) >> 12), 4, 5, 6, 7, 1, 0, 3, 2 ) << 12);

		memcpy( &rom[ i ], &buf[ ofst ], 0x100 );
	}

	free( buf );

	buf = malloc(0x900000);
	memcpy( buf, rom, 0x900000 );

	memcpy( &rom[0x100000], &buf[0x800000], 0x100000 );
	memcpy( &rom[0x200000], &buf[0x100000], 0x700000 );

	free(buf);
}

void kof2003_sx_decrypt( void )
{
	int i;
	int tx_size = memory_region_length( REGION_GFX1 );
	int rom_size = memory_region_length( REGION_GFX3 );
	UINT8 *src;
	UINT8 *dst;

	src = memory_region( REGION_GFX3 ) + rom_size - 0x1000000 - 0x80000;
	dst = memory_region( REGION_GFX1 );

	for( i = 0; i < tx_size / 2; i++ ){
		dst[ i ] = src[ (i & ~0x1f) + ((i & 7) << 2) + ((~i & 8) >> 2) + ((i & 0x10) >> 4) ];
	}

	src = memory_region( REGION_GFX3 ) + rom_size - 0x80000;
	dst = memory_region( REGION_GFX1 ) + 0x80000;

	for( i = 0; i < tx_size / 2; i++ ){
		dst[ i ] = src[ (i & ~0x1f) + ((i & 7) << 2) + ((~i & 8) >> 2) + ((i & 0x10) >> 4) ];
	}

	dst = memory_region( REGION_GFX1 );
	for( i = 0; i < tx_size; i++ ){
		dst[ i ] = BITSWAP8( dst[ i ] ^ 0xd2, 4, 0, 7, 2, 5, 1, 6, 3 );
	}
}

void kf2k3pcb_decrypt_68k( void )
{
	static const unsigned char xor2[ 0x20 ] = { 0xb4, 0x0f, 0x40, 0x6c, 0x38, 0x07, 0xd0, 0x3f, 0x53, 0x08, 0x80, 0xaa, 0xbe, 0x07, 0xc0, 0xfa, 0xd0, 0x08, 0x10, 0xd2, 0xf1, 0x03, 0x70, 0x7e, 0x87, 0x0b, 0x40, 0xf6, 0x2a, 0x0a, 0xe0, 0xf9 };
	int i;
	int ofst;
	int rom_size = 0x900000;
	UINT8 *rom = memory_region( REGION_CPU1 );
	UINT8 *buf = malloc( rom_size );

	for (i = 0; i < 0x100000; i++)
	{
		rom[ 0x800000 + i ] ^= rom[ 0x100002 | i ];
	}
	for( i = 0x100000; i < 0x800000; i++ )
	{
		rom[ i ] ^= xor2[ (i % 0x20) ];
	}
	for( i = 0x100000; i < 0x800000; i += 4 )
	{
		UINT16 *rom16 = (UINT16*)&rom[ i + 1 ];
		*rom16 = BITSWAP16( *rom16, 15, 14, 13, 12, 4, 5, 6, 7, 8, 9, 10, 11, 3, 2, 1, 0 );
	}
	for( i = 0; i < 0x0100000 / 0x10000; i++ )
	{
		ofst = (i & 0xf0) + BITSWAP8( (i & 0x0f), 7, 6, 5, 4, 1, 0, 3, 2 );
		memcpy( &buf[ i * 0x10000 ], &rom[ ofst * 0x10000 ], 0x10000 );
	}
	for( i = 0x100000; i < 0x900000; i += 0x100 )
	{
		ofst = (i & 0xf000ff) + ((i & 0x000f00) ^ 0x00300) + (BITSWAP8( ((i & 0x0ff000) >> 12), 4, 5, 6, 7, 1, 0, 3, 2 ) << 12);
		memcpy( &buf[ i ], &rom[ ofst ], 0x100 );
	}
	memcpy (&rom[0x000000], &buf[0x000000], 0x100000);
	memcpy (&rom[0x100000], &buf[0x800000], 0x100000);
	memcpy (&rom[0x200000], &buf[0x100000], 0x700000);
	free( buf );
}

void kf2k3pcb_gfx_decrypt( void )
{
	static const unsigned char xor[ 4 ] = { 0x34, 0x21, 0xc4, 0xe9 };
	int i;
	int ofst;
	int rom_size = memory_region_length( REGION_GFX3 );
	UINT8 *rom = memory_region( REGION_GFX3 );
	UINT8 *buf = malloc( rom_size );

	for ( i = 0; i < rom_size; i++ )
	{
		rom[ i ] ^= xor[ (i % 4) ];
	}
	for ( i = 0; i < rom_size; i+=4 )
	{
		UINT32 *rom32 = (UINT32*)&rom[ i ];
		*rom32 = BITSWAP32( *rom32, 0x09, 0x0d, 0x13, 0x00, 0x17, 0x0f, 0x03, 0x05, 0x04, 0x0c, 0x11, 0x1e, 0x12, 0x15, 0x0b, 0x06, 0x1b, 0x0a, 0x1a, 0x1c, 0x14, 0x02, 0x0e, 0x1d, 0x18, 0x08, 0x01, 0x10, 0x19, 0x1f, 0x07, 0x16 );
	}
	memcpy( buf, rom, rom_size );
	for ( i = 0; i < rom_size; i+=4 )
	{
		ofst = BITSWAP24( (i & 0x7fffff), 0x17, 0x15, 0x0a, 0x14, 0x13, 0x16, 0x12, 0x11, 0x10, 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00 );
		ofst ^= 0x000000;
		ofst += (i & 0xff800000);;
		memcpy( &rom[ ofst ], &buf[ i ], 0x04 );
	}
	free( buf );
}

void kf2k3pcb_decrypt_s1data( void )
{
	UINT8 *src;
	UINT8 *dst;
	int i;
	int tx_size = memory_region_length( REGION_GFX1 );
	int srom_size = memory_region_length( REGION_GFX3 );

	src = memory_region( REGION_GFX3 ) + srom_size - 0x1000000 - 0x80000; /* Decrypt S */
	dst = memory_region( REGION_GFX1 );

	for( i = 0; i < tx_size / 2; i++ )
	{
		dst[ i ] = src[ (i & ~0x1f) + ((i & 7) << 2) + ((~i & 8) >> 2) + ((i & 0x10) >> 4) ];
	}

	src = memory_region( REGION_GFX3 ) + srom_size - 0x80000;
	dst = memory_region( REGION_GFX1 ) + 0x80000;

	for( i = 0; i < tx_size / 2; i++ )
	{
		dst[ i ] = src[ (i & ~0x1f) + ((i & 7) << 2) + ((~i & 8) >> 2) + ((i & 0x10) >> 4) ];
	}

	dst = memory_region( REGION_GFX1 );

	for( i = 0; i < tx_size; i++ )
	{
		dst[ i ] = BITSWAP8( dst[ i ] ^ 0xd2, 4, 0, 7, 2, 5, 1, 6, 3 );
	}
}

void kof2003biosdecode(void)
{
	static const UINT8 address[0x80]={
		0xb9,0xb8,0x36,0x37,0x3d,0x3c,0xb2,0xb3,
		0xb9,0xb8,0x36,0x37,0x3d,0x3c,0xb2,0xb3,
		0x65,0xea,0x6f,0xe0,0xe1,0x6e,0xeb,0x64,
		0x65,0xea,0x6f,0xe0,0xe1,0x6e,0xeb,0x64,
		0x45,0xca,0x47,0xc8,0xc9,0x46,0xcb,0x44,
		0x45,0xca,0x47,0xc8,0xc9,0x46,0xcb,0x44,
		0x9a,0x15,0x98,0x17,0x1e,0x91,0x1c,0x93,
		0x9a,0x15,0x98,0x17,0x1e,0x91,0x1c,0x93,
		0x7e,0xf1,0x7c,0xf3,0xf0,0x7f,0xf2,0x7d,
		0x7e,0xf1,0x7c,0xf3,0xf0,0x7f,0xf2,0x7d,
		0x27,0xa8,0x25,0xaa,0xa3,0x2c,0xa1,0x2e,
		0x27,0xa8,0x25,0xaa,0xa3,0x2c,0xa1,0x2e,
		0x04,0x8b,0x06,0x89,0x80,0x0f,0x82,0x0d,
		0x04,0x8b,0x06,0x89,0x80,0x0f,0x82,0x0d,
		0xd3,0xd2,0x5c,0x5d,0x57,0x56,0xd8,0xd9,
		0xd3,0xd2,0x5c,0x5d,0x57,0x56,0xd8,0xd9,
	};
	UINT16*src= (UINT16*)memory_region( REGION_USER1 );
	UINT16*buf= (UINT16*)malloc(0x80000);
	int	a,addr;

		for (a=0;a<0x80000/2;a++)
		{
			/*data xor */
			if (src[a] & 0x0004)	src[a] ^= 0x0001;
			if (src[a] & 0x0010)	src[a] ^= 0x0002;
			if (src[a] & 0x0020)	src[a] ^= 0x0008;
			/*address xor */
			addr  = a & ~0xff;
			addr |= address[a & 0x7f];
			if ( a & 0x00008)	addr ^= 0x0008;
			if ( a & 0x00080)	addr ^= 0x0080;
			if ( a & 0x00200)	addr ^= 0x0100;
			if (~a & 0x02000)	addr ^= 0x0400;
			if (~a & 0x10000)	addr ^= 0x1000;
			if ( a & 0x02000)	addr ^= 0x8000;
			buf[addr]=src[a];
		}
		memcpy(src,buf,0x80000);
		free(buf);
}

void svcchaos_px_decrypt( void )
{
	const unsigned char xor1[ 0x20 ] = {
		0x3b, 0x6a, 0xf7, 0xb7, 0xe8, 0xa9, 0x20, 0x99, 0x9f, 0x39, 0x34, 0x0c, 0xc3, 0x9a, 0xa5, 0xc8,
		0xb8, 0x18, 0xce, 0x56, 0x94, 0x44, 0xe3, 0x7a, 0xf7, 0xdd, 0x42, 0xf0, 0x18, 0x60, 0x92, 0x9f,
	};

	const unsigned char xor2[ 0x20 ] = {
		0x69, 0x0b, 0x60, 0xd6, 0x4f, 0x01, 0x40, 0x1a, 0x9f, 0x0b, 0xf0, 0x75, 0x58, 0x0e, 0x60, 0xb4,
		0x14, 0x04, 0x20, 0xe4, 0xb9, 0x0d, 0x10, 0x89, 0xeb, 0x07, 0x30, 0x90, 0x50, 0x0e, 0x20, 0x26,
	};

	int i;
	int ofst;
	UINT8 *rom, *buf;

	rom = memory_region( REGION_CPU1 );

	for( i = 0; i < 0x100000; i++ ){
		rom[ i ] ^= xor1[ (i % 0x20) ];
	}

	for( i = 0x100000; i < 0x800000; i++ ){
		rom[ i ] ^= xor2[ (i % 0x20) ];
	}

	for( i = 0x100000; i < 0x800000; i += 4 ){
		UINT16 *rom16 = (UINT16*)&rom[ i + 1 ];
		*rom16 = BITSWAP16( *rom16, 15, 14, 13, 12, 10, 11, 8, 9, 6, 7, 4, 5, 3, 2, 1, 0 );
	}

	buf = malloc( 0x800000 );
	memcpy( buf, rom, 0x800000 );

	for( i = 0; i < 0x0100000 / 0x10000; i++ ){
		ofst = (i & 0xf0) + BITSWAP8( (i & 0x0f), 7, 6, 5, 4, 2, 3, 0, 1 );
		memcpy( &rom[ i * 0x10000 ], &buf[ ofst * 0x10000 ], 0x10000 );
	}

	for( i = 0x100000; i < 0x800000; i += 0x100 ){
		ofst = (i & 0xf000ff) + 
			   ((i & 0x000f00) ^ 0x00a00) +
			   (BITSWAP8( ((i & 0x0ff000) >> 12), 4, 5, 6, 7, 1, 0, 3, 2 ) << 12);

		memcpy( &rom[ i ], &buf[ ofst ], 0x100 );
	}

	free( buf );

	buf = malloc( 0x800000 );
	memcpy( buf, rom, 0x800000 );
	memcpy( &rom[ 0x100000 ], &buf[ 0x700000 ], 0x100000 );
	memcpy( &rom[ 0x200000 ], &buf[ 0x100000 ], 0x600000 );
	free( buf );
}

void svcchaos_vx_decrypt( void )
{
	const unsigned char xor[ 0x08 ] = {
		0xc3, 0xfd, 0x81, 0xac, 0x6d, 0xe7, 0xbf, 0x9e
	};

	int ofst;

	int rom_size = memory_region_length( REGION_SOUND1 );
	UINT8 *rom = memory_region( REGION_SOUND1 );
	UINT8 *buf = malloc( rom_size );
	int i;

	memcpy( buf, rom, rom_size );

	for( i=0;i<rom_size;i++ ){
		ofst = (i & 0xfefffe) |
			   ((i & 0x010000) >> 16) |
			   ((i & 0x000001) << 16);

		ofst ^= 0xc2000;

		rom[ ofst ] = buf[ ((i + 0xffac28) & 0xffffff) ] ^ xor[ (ofst & 0x07) ];
	}

	free( buf );
}

/* svcchaos has an additional scramble on top of the standard CMC scrambling */

void svcpcb_gfx_decrypt( void )
{
	static const unsigned char xor[ 4 ] = { 0x34, 0x21, 0xc4, 0xe9 };
	int i;
	int ofst;
	int rom_size = memory_region_length( REGION_GFX3 );
	UINT8 *rom = memory_region( REGION_GFX3 );
	UINT8 *buf = malloc( rom_size );

	for( i = 0; i < rom_size; i++ )
	{
		rom[ i ] ^= xor[ (i % 4) ];
	}
	for( i = 0; i < rom_size; i += 4 )
	{
		UINT32 *rom32 = (UINT32*)&rom[ i ];
		*rom32 = BITSWAP32( *rom32, 0x09, 0x0d, 0x13, 0x00, 0x17, 0x0f, 0x03, 0x05, 0x04, 0x0c, 0x11, 0x1e, 0x12, 0x15, 0x0b, 0x06, 0x1b, 0x0a, 0x1a, 0x1c, 0x14, 0x02, 0x0e, 0x1d, 0x18, 0x08, 0x01, 0x10, 0x19, 0x1f, 0x07, 0x16 );
	}
	memcpy( buf, rom, rom_size );
	for( i = 0; i < rom_size / 4; i++ )
	{
		ofst =  BITSWAP24( (i & 0x1fffff), 0x17, 0x16, 0x15, 0x04, 0x0b, 0x0e, 0x08, 0x0c, 0x10, 0x00, 0x0a, 0x13, 0x03, 0x06, 0x02, 0x07, 0x0d, 0x01, 0x11, 0x09, 0x14, 0x0f, 0x12, 0x05 );
		ofst ^= 0x0c8923;
		ofst += (i & 0xffe00000);
		memcpy( &rom[ i * 4 ], &buf[ ofst * 4 ], 0x04 );
	}
	free( buf );
}

/* and a further swap on the s1 data */
void svcpcb_s1data_decrypt( void )
{
	int i;
	UINT8 *s1 = memory_region( REGION_GFX1 );
	size_t s1_size = memory_region_length( REGION_GFX1 );

	for( i = 0; i < s1_size; i++ ) /* Decrypt S */
	{
		s1[ i ] = BITSWAP8( s1[ i ] ^ 0xd2, 4, 0, 7, 2, 5, 1, 6, 3 );
	}
}

void svcplus_px_decrypt( void )
{
	static const int sec[] = {
		0x00, 0x03, 0x02, 0x05, 0x04, 0x01
	};
	int size = memory_region_length( REGION_CPU1 );
	UINT8 *src = memory_region( REGION_CPU1 );
	UINT8 *dst = malloc( size );
	int i;
	int ofst;
	memcpy( dst, src, size );
	for( i = 0; i < size / 2; i++ ){
		ofst = BITSWAP24( (i & 0xfffff), 0x17, 0x16, 0x15, 0x14, 0x13, 0x00, 0x01, 0x02,
										 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
										 0x07, 0x06, 0x05, 0x04, 0x03, 0x10, 0x11, 0x12 );
		ofst ^= 0x0f0007;
		ofst += (i & 0xff00000);
		memcpy( &src[ i * 0x02 ], &dst[ ofst * 0x02 ], 0x02 );
	}
	memcpy( dst, src, size );
	for( i = 0; i < 6; i++ ){
		memcpy( &src[ i * 0x100000 ], &dst[ sec[ i ] * 0x100000 ], 0x100000 );
	}
	free( dst );
}

void svcplus_px_hack( void )
{
	/* patched by the protection chip? */
	UINT8 *src = memory_region( REGION_CPU1 );
	src[ 0x0f8010 ] = 0x40;
	src[ 0x0f8011 ] = 0x04;
	src[ 0x0f8012 ] = 0x00;
	src[ 0x0f8013 ] = 0x10;
	src[ 0x0f8014 ] = 0x40;
	src[ 0x0f8015 ] = 0x46;
	src[ 0x0f8016 ] = 0xc1;
	src[ 0x0f802c ] = 0x16;
}

void svcplusa_px_decrypt( void )
{
	int i;
	static const int sec[] = {
		0x01, 0x02, 0x03, 0x04, 0x05, 0x00
	};
	int size = memory_region_length( REGION_CPU1 );
	UINT8 *src = memory_region( REGION_CPU1 );
	UINT8 *dst = malloc( size );
	memcpy( dst, src, size );
	for( i = 0; i < 6; i++ ){
		memcpy( &src[ i * 0x100000 ], &dst[ sec[ i ] * 0x100000 ], 0x100000 );
	}
	free( dst );
}

void svcsplus_px_decrypt( void )
{
	static const int sec[] = {
		0x06, 0x07, 0x01, 0x02, 0x03, 0x04, 0x05, 0x00
	};
	int size = memory_region_length( REGION_CPU1 );
	UINT8 *src = memory_region( REGION_CPU1 );
	UINT8 *dst = malloc( size );
	int i;
	int ofst;
	memcpy( dst, src, size );
	for( i = 0; i < size / 2; i++ ){
		ofst = BITSWAP16( (i & 0x007fff), 0x0f, 0x00, 0x08, 0x09, 0x0b, 0x0a, 0x0c, 0x0d,
										  0x04, 0x03, 0x01, 0x07, 0x06, 0x02, 0x05, 0x0e );

		ofst += (i & 0x078000);
		ofst += sec[ (i & 0xf80000) >> 19 ] << 19;
		memcpy( &src[ i * 2 ], &dst[ ofst * 2 ], 0x02 );
	}
	free( dst );
}

void svcsplus_px_hack( void )
{
	/* patched by the protection chip? */
	UINT16 *mem16 = (UINT16 *)memory_region(REGION_CPU1);
	mem16[0x9e90/2] = 0x000f;
	mem16[0x9e92/2] = 0xc9c0;
	mem16[0xa10c/2] = 0x4eb9;
	mem16[0xa10e/2] = 0x000e;
	mem16[0xa110/2] = 0x9750;
}


